{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "5f944883-a20b-4337-beeb-a4d97edba8e2",
   "metadata": {},
   "source": [
    "# 实验9 基于CNN的图像识别"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "72fb5e09-6651-4c19-9103-3ecfb05773ff",
   "metadata": {},
   "source": [
    "## 读取非MNIST数据"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "f4419f33-3a04-4f51-abe5-caba70fbd326",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Test set size: 10000\n",
      "Training set size: 60000\n"
     ]
    }
   ],
   "source": [
    "import torch\n",
    "import torchvision\n",
    "import torchvision.transforms as transforms\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "label_size = 18 # Label size\n",
    "ticklabel_size = 14 # Tick label size\n",
    "    \n",
    "# Define a transform to normalize the data\n",
    "transform = transforms.Compose([\n",
    "    transforms.ToTensor()\n",
    "])\n",
    "\n",
    "# Load test data from the MNIST\n",
    "testset = torchvision.datasets.MNIST(root='./Data', train=False, download=False, transform=transform)\n",
    "print(f\"Test set size: {len(testset)}\")\n",
    "\n",
    "# Load training data from the MNIST\n",
    "trainset = torchvision.datasets.MNIST(root='./Data', train=True, download=False, transform=transform)\n",
    "print(f\"Training set size: {len(trainset)}\")\n",
    "\n",
    "# Rate of trX and cvX\n",
    "tr_cv_rate = 0.8\n",
    "\n",
    "# Create a list to store indices for each class unique()\n",
    "class_indices = [[] for _ in range(10)]  # 10 classes in MNIST\n",
    "\n",
    "# Populate class_indices\n",
    "for idx, (_, label) in enumerate(trainset):\n",
    "    class_indices[label].append(idx)\n",
    "\n",
    "# Calculate the number of samples for each class in training and validation sets\n",
    "train_size_per_class = int(tr_cv_rate * min(len(indices) for indices in class_indices))\n",
    "val_size_per_class = min(len(indices) for indices in class_indices) - train_size_per_class\n",
    "\n",
    "# Create balanced train and validation sets\n",
    "train_indices = []\n",
    "val_indices = []\n",
    "for indices in class_indices:\n",
    "    train_indices.extend(indices[:train_size_per_class])\n",
    "    val_indices.extend(indices[train_size_per_class:train_size_per_class + val_size_per_class])\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0d586fa0-580d-49bb-9da9-8b616f3235c0",
   "metadata": {},
   "source": [
    "## 使用训练数据生成DataSet和DataLoader对象用于模型训练"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "99ba1866-8b5c-4089-a15e-6a0691b80756",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Number of training samples: 43360\n",
      "Number of cross-validation samples: 10850\n"
     ]
    }
   ],
   "source": [
    "# Create Subset datasets\n",
    "from torch.utils.data import Subset\n",
    "trX = Subset(trainset, train_indices)\n",
    "cvX = Subset(trainset, val_indices)\n",
    "\n",
    "print(f\"Number of training samples: {len(trX)}\")\n",
    "print(f\"Number of cross-validation samples: {len(cvX)}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "33c5ed6b-604e-479e-978b-8959563cf73c",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "image_channels is 1\n",
      "tensor([[0., 0., 0., 0., 1., 0., 0., 0., 0., 0.],\n",
      "        [0., 0., 0., 0., 0., 0., 0., 0., 0., 1.],\n",
      "        [0., 0., 0., 0., 0., 0., 0., 0., 0., 1.],\n",
      "        [0., 0., 0., 0., 0., 0., 0., 0., 0., 1.],\n",
      "        [1., 0., 0., 0., 0., 0., 0., 0., 0., 0.],\n",
      "        [0., 0., 0., 0., 0., 0., 0., 0., 1., 0.],\n",
      "        [0., 0., 0., 1., 0., 0., 0., 0., 0., 0.],\n",
      "        [0., 0., 0., 1., 0., 0., 0., 0., 0., 0.],\n",
      "        [0., 0., 0., 0., 0., 0., 0., 1., 0., 0.],\n",
      "        [0., 0., 0., 0., 0., 1., 0., 0., 0., 0.],\n",
      "        [0., 1., 0., 0., 0., 0., 0., 0., 0., 0.],\n",
      "        [0., 1., 0., 0., 0., 0., 0., 0., 0., 0.],\n",
      "        [1., 0., 0., 0., 0., 0., 0., 0., 0., 0.],\n",
      "        [0., 0., 0., 0., 0., 0., 0., 0., 0., 1.],\n",
      "        [0., 0., 0., 1., 0., 0., 0., 0., 0., 0.],\n",
      "        [0., 0., 0., 0., 0., 0., 0., 0., 1., 0.],\n",
      "        [0., 0., 1., 0., 0., 0., 0., 0., 0., 0.],\n",
      "        [0., 0., 0., 0., 0., 0., 0., 0., 1., 0.],\n",
      "        [0., 0., 0., 0., 0., 1., 0., 0., 0., 0.],\n",
      "        [0., 0., 0., 0., 1., 0., 0., 0., 0., 0.],\n",
      "        [0., 1., 0., 0., 0., 0., 0., 0., 0., 0.],\n",
      "        [0., 0., 0., 1., 0., 0., 0., 0., 0., 0.],\n",
      "        [0., 0., 0., 0., 0., 0., 0., 0., 1., 0.],\n",
      "        [0., 0., 0., 0., 0., 0., 0., 0., 1., 0.],\n",
      "        [0., 0., 0., 0., 0., 0., 0., 0., 1., 0.],\n",
      "        [0., 0., 0., 0., 0., 1., 0., 0., 0., 0.],\n",
      "        [0., 0., 1., 0., 0., 0., 0., 0., 0., 0.],\n",
      "        [0., 0., 0., 0., 0., 0., 1., 0., 0., 0.],\n",
      "        [0., 0., 0., 0., 0., 0., 0., 1., 0., 0.],\n",
      "        [0., 0., 0., 0., 1., 0., 0., 0., 0., 0.],\n",
      "        [0., 0., 1., 0., 0., 0., 0., 0., 0., 0.],\n",
      "        [1., 0., 0., 0., 0., 0., 0., 0., 0., 0.],\n",
      "        [0., 1., 0., 0., 0., 0., 0., 0., 0., 0.],\n",
      "        [0., 0., 0., 0., 0., 0., 1., 0., 0., 0.],\n",
      "        [0., 0., 0., 0., 1., 0., 0., 0., 0., 0.],\n",
      "        [0., 0., 0., 0., 0., 0., 1., 0., 0., 0.],\n",
      "        [0., 1., 0., 0., 0., 0., 0., 0., 0., 0.],\n",
      "        [0., 0., 0., 0., 0., 0., 0., 0., 1., 0.],\n",
      "        [1., 0., 0., 0., 0., 0., 0., 0., 0., 0.],\n",
      "        [0., 0., 0., 0., 0., 0., 1., 0., 0., 0.],\n",
      "        [0., 1., 0., 0., 0., 0., 0., 0., 0., 0.],\n",
      "        [0., 0., 0., 0., 1., 0., 0., 0., 0., 0.]])\n"
     ]
    }
   ],
   "source": [
    "batch_size = 42 # Define training batch 1，\n",
    "\n",
    "def one_hot_collate(batch):\n",
    "    data = torch.stack([item[0] for item in batch])\n",
    "    labels = torch.tensor([item[1] for item in batch])\n",
    "    one_hot_labels = torch.zeros(labels.size(0), 10)  # 10 classes in MNIST 【0，1，0，0】\n",
    "    one_hot_labels.scatter_(1, labels.unsqueeze(1), 1)\n",
    "    return data, one_hot_labels\n",
    "\n",
    "trLoader = torch.utils.data.DataLoader(trX, batch_size=batch_size, shuffle=True, num_workers=0, collate_fn=one_hot_collate)\n",
    "cvLoader = torch.utils.data.DataLoader(cvX, batch_size=batch_size, shuffle=False, num_workers=0, collate_fn=one_hot_collate)\n",
    "teLoader = torch.utils.data.DataLoader(testset, batch_size=batch_size, shuffle=False, num_workers=0, collate_fn=one_hot_collate)\n",
    "\n",
    "# Get a batch of training data\n",
    "dataiter = iter(trLoader)\n",
    "data, labels = next(dataiter)\n",
    "\n",
    "image_channels = data[0].numpy().shape[0]\n",
    "print(f'image_channels is {image_channels}')\n",
    "print(labels)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3208c318-950c-40b7-ab86-2895f606eafd",
   "metadata": {},
   "source": [
    "## 使用torch.nn定义CNN类，可自定隐藏层数和卷积核数量"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "3e39f0b1-9c61-4cb3-bc70-604ecc867f42",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CNN(\n",
      "  (conv1): Conv2d(1, 32, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n",
      "  (pool1): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)\n",
      "  (conv2): Conv2d(32, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n",
      "  (pool2): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)\n",
      "  (fc1): Linear(in_features=3136, out_features=100, bias=True)\n",
      "  (fc2): Linear(in_features=100, out_features=10, bias=True)\n",
      "  (softmax): Softmax(dim=1)\n",
      ")\n"
     ]
    }
   ],
   "source": [
    "import torch.nn as nn\n",
    "import torch.nn.functional as F\n",
    "import torch.optim as optim\n",
    "\n",
    "class CNN(nn.Module):\n",
    "    def __init__(self, image_channels, num_classes):\n",
    "        super(CNN, self).__init__()\n",
    "        \n",
    "        # First convolutional layer\n",
    "        self.conv1 = nn.Conv2d(in_channels=image_channels, out_channels=32, kernel_size=3, padding=1)\n",
    "        self.pool1 = nn.MaxPool2d(kernel_size=2, stride=2)\n",
    "        \n",
    "        # Second convolutional layer\n",
    "        self.conv2 = nn.Conv2d(32, 64, kernel_size=3, padding=1)\n",
    "        self.pool2 = nn.MaxPool2d(kernel_size=2, stride=2)\n",
    "        \n",
    "        # Fully connected layers\n",
    "        self.fc1 = nn.Linear(64 * 7 * 7, 100)  # After two 2x2 max pools, 28x28 -> 7x7\n",
    "        self.fc2 = nn.Linear(100, num_classes)  # 10 classes output\n",
    "\n",
    "        # Softmax\n",
    "        self.softmax = nn.Softmax(dim=1)\n",
    "        \n",
    "    def forward(self, x):\n",
    "        # Remove the reshape operation and directly use x\n",
    "        x = F.relu(self.conv1(x))\n",
    "        x = self.pool1(x)\n",
    "        \n",
    "        # Second conv layer\n",
    "        x = F.relu(self.conv2(x))\n",
    "        x = self.pool2(x)\n",
    "        \n",
    "        # Flatten the output for the fully connected layers\n",
    "        x = x.view(-1, 64 * 7 * 7)\n",
    "        \n",
    "        # Fully connected layers\n",
    "        x = F.relu(self.fc1(x))\n",
    "        x = self.fc2(x)\n",
    "        \n",
    "        # Softmax\n",
    "        x = self.softmax(x)\n",
    "        \n",
    "        return x\n",
    "\n",
    "# Initialize the model\n",
    "model = CNN(image_channels, 10)\n",
    "if torch.cuda.is_available():\n",
    "    model = model.cuda()\n",
    "\n",
    "# Display model architecture\n",
    "print(model)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6b64316a-1042-4128-9199-d373897be49b",
   "metadata": {},
   "source": [
    "## 用Adam的优化方式训练模型"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "8b75c2c9-96aa-40b9-b502-f53224efd7d3",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch [1/21], Train Loss: 1.5701, CV Loss: 1.5007\n",
      "Epoch [2/21], Train Loss: 1.4905, CV Loss: 1.4871\n",
      "Epoch [3/21], Train Loss: 1.4834, CV Loss: 1.4815\n",
      "Epoch [4/21], Train Loss: 1.4784, CV Loss: 1.4819\n",
      "Epoch [5/21], Train Loss: 1.4770, CV Loss: 1.4822\n",
      "Epoch [6/21], Train Loss: 1.4737, CV Loss: 1.4796\n",
      "Epoch [7/21], Train Loss: 1.4727, CV Loss: 1.4845\n",
      "Epoch [8/21], Train Loss: 1.4724, CV Loss: 1.4827\n",
      "Epoch [9/21], Train Loss: 1.4703, CV Loss: 1.4802\n",
      "Epoch [10/21], Train Loss: 1.4708, CV Loss: 1.4845\n",
      "Epoch [11/21], Train Loss: 1.4699, CV Loss: 1.4782\n",
      "Epoch [12/21], Train Loss: 1.4701, CV Loss: 1.4783\n",
      "Epoch [13/21], Train Loss: 1.4687, CV Loss: 1.4775\n",
      "Epoch [14/21], Train Loss: 1.4681, CV Loss: 1.4779\n",
      "Epoch [15/21], Train Loss: 1.4677, CV Loss: 1.4782\n",
      "Epoch [16/21], Train Loss: 1.4680, CV Loss: 1.4789\n",
      "Epoch [17/21], Train Loss: 1.4684, CV Loss: 1.4774\n",
      "Epoch [18/21], Train Loss: 1.4683, CV Loss: 1.4769\n",
      "Epoch [19/21], Train Loss: 1.4670, CV Loss: 1.4774\n",
      "Epoch [20/21], Train Loss: 1.4668, CV Loss: 1.4751\n",
      "Epoch [21/21], Train Loss: 1.4664, CV Loss: 1.4762\n"
     ]
    }
   ],
   "source": [
    "# Define loss function and optimizer\n",
    "criterion = nn.CrossEntropyLoss() # Loss\n",
    "optimizer = torch.optim.Adam(model.parameters()) # Adam\n",
    "\n",
    "# Lists to store losses\n",
    "train_losses = []\n",
    "cv_losses = []\n",
    "\n",
    "# Number of epochs\n",
    "num_epochs = 21\n",
    "\n",
    "for epoch in range(num_epochs):\n",
    "    model.train()\n",
    "    batch_losses = []\n",
    "    \n",
    "    for batch_x, batch_y in trLoader:\n",
    "        # Forward pass\n",
    "        outputs = model(batch_x)\n",
    "        loss = criterion(outputs, batch_y)\n",
    "        \n",
    "        # Backward pass and optimize\n",
    "        optimizer.zero_grad()\n",
    "        loss.backward()\n",
    "        optimizer.step()\n",
    "        \n",
    "        batch_losses.append(loss.item())\n",
    "    \n",
    "    # Calculate average training loss for this epoch\n",
    "    avg_train_loss = sum(batch_losses) / len(batch_losses)\n",
    "    train_losses.append(avg_train_loss)\n",
    "    \n",
    "    # Evaluate on cross-validation set\n",
    "    model.eval()\n",
    "    cv_batch_losses = []\n",
    "    with torch.no_grad():\n",
    "        for cv_x, cv_y in cvLoader:\n",
    "            cv_outputs = model(cv_x)\n",
    "            cv_loss = criterion(cv_outputs, cv_y)\n",
    "            cv_batch_losses.append(cv_loss.item())\n",
    "    \n",
    "    avg_cv_loss = sum(cv_batch_losses) / len(cv_batch_losses)\n",
    "    cv_losses.append(avg_cv_loss)\n",
    "    \n",
    "    print(f'Epoch [{epoch+1}/{num_epochs}], Train Loss: {avg_train_loss:.4f}, CV Loss: {avg_cv_loss:.4f}')"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "aa3a0d30-c81b-4ef9-b30f-791d49d53645",
   "metadata": {},
   "source": [
    "## 在验证或测试集上测试模型性能，画出学习曲线并分析结果"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "017c2cd0-81f0-4dde-a5d2-999bb4b30408",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Accuracy on training set: 99.48%\n",
      "Accuracy on cross-validation set: 98.52%\n"
     ]
    },
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAA1cAAAHUCAYAAADWedKvAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguNCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8fJSN1AAAACXBIWXMAAA9hAAAPYQGoP6dpAAB8AklEQVR4nO3dd3hTZf8G8Ptkdy9a2tLFLHuvgmwEyhAEBBQZivoquF7QF1ERnCiC4AInIKKIUOHnK8imgAyBV5YyZBTaQivQ0t0maXJ+f5wmbdp0p02T3p/rypWcmSenpyU3z3O+RxBFUQQRERERERFVi8zeDSAiIiIiInIGDFdEREREREQ2wHBFRERERERkAwxXRERERERENsBwRUREREREZAMMV0RERERERDbAcEVERERERGQDDFdEREREREQ2wHBFRERERERkAwxXRFRvCIJQoUdsbGy13mfhwoUQBKFK28bGxtqkDXXd9OnTERERUaF1jUYjvv32WwwePBgNGjSAUqlEQEAARo4cif/+978wGo0129hqOn36NARBwEsvvVTqOpcuXYIgCHj22WcrvF9r51n//v3Rv3//cre9du0aBEHAmjVrKvx+JufOncPChQtx7dq1Essq83O1NUEQ8PTTT9vlvYmITBT2bgARUW05cuSIxfSbb76Jffv2Ye/evRbzW7duXa33eeyxxzBs2LAqbdu5c2ccOXKk2m1wFnl5eRgzZgx27tyJSZMmYeXKlQgMDMTt27exfft2PPDAA9iwYQNGjx5t76aWqkOHDujSpQvWrl2Lt99+G3K5vMQ6q1evBgDMmDGjWu+1YsWKam1fEefOncPrr7+O/v37lwhS8+fPx3PPPVfjbSAiqqsYroio3ujZs6fFtL+/P2QyWYn5xeXk5MDV1bXC7xMSEoKQkJAqtdHT07Pc9tQns2fPxo4dO/DNN99g6tSpFsvGjh2LF198Ebm5uaVur9frIQgCFAr7/nM3Y8YMzJw5E7/++itGjhxpscxgMGDt2rXo0qULOnToUK33sXcob9q0qV3fn4jI3jgskIioiP79+6Nt27Y4cOAAevXqBVdXVzz66KMAgA0bNmDIkCEICgqCi4sLWrVqhZdeegnZ2dkW+7A2XCsiIgIjR47E9u3b0blzZ7i4uKBly5ZYtWqVxXrWhgVOnz4d7u7uuHz5MoYPHw53d3eEhoZizpw50Gq1FtsnJiZi/Pjx8PDwgLe3NyZPnozjx49XaAjY7du3MXPmTLRu3Rru7u4ICAjAwIEDcfDgQYv1TEPKlixZgg8++ACNGzeGu7s7oqKicPTo0RL7XbNmDSIjI6FWq9GqVSusXbu2zHaYJCcn46uvvsLQoUNLBCuT5s2bo3379gAKj923336LOXPmoFGjRlCr1bh8+TIAYNWqVejQoQM0Gg18fX1x//334/z58xb7u3r1KiZNmoTg4GCo1Wo0bNgQgwYNwqlTp8zr7N27F/3794efnx9cXFwQFhaGcePGIScnp9TP8tBDD8HFxcXcQ1XUzp07cePGjUqfZ9ZYGxZ48+ZNTJgwAR4eHvDy8sLEiRORnJxcYtsTJ05g0qRJiIiIgIuLCyIiIvDggw/i+vXr5nXWrFmDBx54AAAwYMAA81Ba07llbVhgXl4e5s2bh8aNG0OlUqFRo0aYNWsW0tLSLNar6O9IdaSmpmLmzJlo1KgRVCoVmjRpgldeeaXE79HGjRvRo0cPeHl5wdXVFU2aNDH/fABpqOpbb72FyMhIuLi4wNvbG+3bt8eHH35os7YSkWNizxURUTFJSUl4+OGH8Z///AfvvPMOZDLp/6EuXbqE4cOH4/nnn4ebmxsuXLiA9957D8eOHSsxtNCa06dPY86cOXjppZfQsGFDfPXVV5gxYwaaNWuGvn37lrmtXq/HfffdhxkzZmDOnDk4cOAA3nzzTXh5eeG1114DAGRnZ2PAgAFITU3Fe++9h2bNmmH79u2YOHFihT53amoqAGDBggUIDAxEVlYWNm/ejP79+2PPnj0lvrR/+umnaNmyJZYvXw5AGhI2fPhwxMXFwcvLC4D0ZfyRRx7B6NGjsXTpUqSnp2PhwoXQarXm41qaffv2Qa/XY8yYMRVqv8m8efMQFRWFzz77DDKZDAEBAVi0aBFefvllPPjgg1i0aBFSUlKwcOFCREVF4fjx42jevDkAYPjw4TAYDFi8eDHCwsJw584dHD582BwErl27hhEjRqBPnz5YtWoVvL29cePGDWzfvh06na7UHk4vLy+MGzcOGzZswO3bt+Hv729etnr1amg0Gjz00EMAqn+eFZWbm4vBgwfj5s2bWLRoEVq0aIGtW7daPSeuXbuGyMhITJo0Cb6+vkhKSsLKlSvRrVs3nDt3Dg0aNMCIESPwzjvv4OWXX8ann36Kzp07Ayi9x0oURYwZMwZ79uzBvHnz0KdPH5w5cwYLFizAkSNHcOTIEajVavP61fkdKU9eXh4GDBiAK1eu4PXXX0f79u1x8OBBLFq0CKdOncLWrVsBSMOHJ06ciIkTJ2LhwoXQaDS4fv26xbFfvHgxFi5ciFdffRV9+/aFXq/HhQsXSgRGIqqHRCKiemratGmim5ubxbx+/fqJAMQ9e/aUua3RaBT1er24f/9+EYB4+vRp87IFCxaIxf+8hoeHixqNRrx+/bp5Xm5urujr6yv+61//Ms/bt2+fCEDct2+fRTsBiD/++KPFPocPHy5GRkaapz/99FMRgPjrr79arPevf/1LBCCuXr26zM9UXH5+vqjX68VBgwaJ999/v3l+XFycCEBs166dmJ+fb55/7NgxEYC4fv16URRF0WAwiMHBwWLnzp1Fo9FoXu/atWuiUqkUw8PDy3z/d999VwQgbt++vULtNR27vn37Wsy/e/eu6OLiIg4fPtxifnx8vKhWq8WHHnpIFEVRvHPnjghAXL58eanvsWnTJhGAeOrUqQq1yVr7PvjgA/O8lJQUUa1Wi5MnT7a6TWXPs379+on9+vUzT69cuVIEIP7f//2fxXqPP/54uedEfn6+mJWVJbq5uYkffvihef7GjRtLnKMm06ZNs/i5bt++XQQgLl682GK9DRs2iADEL774wjyvor8jpQEgzpo1q9Tln332mdXfo/fee08EIO7cuVMURVFcsmSJCEBMS0srdV8jR44UO3bsWG6biKj+4bBAIqJifHx8MHDgwBLzr169ioceegiBgYGQy+VQKpXo168fAJQYXmZNx44dERYWZp7WaDRo0aKFxbCr0giCgFGjRlnMa9++vcW2+/fvh4eHR4liGg8++GC5+zf57LPP0LlzZ2g0GigUCiiVSuzZs8fq5xsxYoRFcQbT8DxTmy5evIibN2/ioYceshgmGR4ejl69elW4TZU1btw4i+kjR44gNzcX06dPt5gfGhqKgQMHYs+ePQAAX19fNG3aFO+//z4++OADnDx5skQlwo4dO0KlUuGJJ57AN998g6tXr5Z4f4PBgPz8fPPDtI9+/fqhadOmFkMDv/vuO2i1WoshZ9U9z4rat28fPDw8cN9991nMN/WSFZWVlYW5c+eiWbNmUCgUUCgUcHd3R3Z2dqXf18TU21P82D/wwANwc3MzH3uT6vyOVKQtbm5uGD9+vMV8U9tMbenWrRsAYMKECfjxxx9x48aNEvvq3r07Tp8+jZkzZ2LHjh3IyMiodvuIyDkwXBERFRMUFFRiXlZWFvr06YPff/8db731FmJjY3H8+HH89NNPAFBmUQUTPz+/EvPUanWFtnV1dYVGoymxbV5ennk6JSUFDRs2LLGttXnWfPDBB3jqqafQo0cPxMTE4OjRozh+/DiGDRtmtY3FP49peJdp3ZSUFABAYGBgiW2tzSvO9CU7Li6uQu03Kf7zM7XD2s81ODjYvFwQBOzZswdDhw7F4sWL0blzZ/j7++PZZ59FZmYmAGn42+7duxEQEIBZs2ahadOmaNq0qcW1NoMGDYJSqTQ/TMFJEAQ8+uijOHv2LE6cOAFAGhLYuHFjDBgwAIBtzrPin93az9/a8X/ooYfwySef4LHHHsOOHTtw7NgxHD9+HP7+/pV+36Lvr1AoLIZBAtKxCAwMNB97k+r8jlSkLYGBgSWuhwwICIBCoTC3pW/fvtiyZQvy8/MxdepUhISEoG3btli/fr15m3nz5mHJkiU4evQooqOj4efnh0GDBpl/rkRUf/GaKyKiYqzdo2rv3r24efMmYmNjzb0IAOrUNRZ+fn44duxYifnWihdYs27dOvTv3x8rV660mG8KFlVpT2nvX5E2DRgwAEqlElu2bMGTTz5Z4fct/vMztSMpKanEujdv3kSDBg3M0+Hh4fj6668BAH///Td+/PFHLFy4EDqdDp999hkAoE+fPujTpw8MBgNOnDiBjz/+GM8//zwaNmyISZMm4fPPP7c4ZkX3P336dLz22mtYtWoVlEolTp48iTfffNPcZlufZxU9J9LT0/HLL79gwYIFFvfj0mq15mvxqvr++fn5Ja4zE0URycnJ5l6i2uDn54fff/8doihanCO3bt1Cfn6+xc9p9OjRGD16NLRaLY4ePYpFixbhoYceQkREBKKioqBQKDB79mzMnj0baWlp2L17N15++WUMHToUCQkJlaouSkTOhT1XREQVYPoyVvTiewD4/PPP7dEcq/r164fMzEz8+uuvFvN/+OGHCm0vCEKJz3fmzJkS9werqMjISAQFBWH9+vUQRdE8//r16zh8+HC52wcGBpp7UUqrMHjlyhWcOXOmzP1ERUXBxcUF69ats5ifmJiIvXv3YtCgQVa3a9GiBV599VW0a9cOf/zxR4nlcrkcPXr0wKeffgoA5nUiIyPRtWtX86No9bzg4GAMGzYM69evx6effgqZTIZp06aZl9v6PBswYAAyMzPx888/W8z//vvvLaYFQYAoiiXe96uvvoLBYLCYV7yHsiymY1v82MfExCA7O7vUY18TBg0ahKysLGzZssVivuncstYWtVqNfv364b333gMAnDx5ssQ63t7eGD9+PGbNmoXU1FSrN1cmovqDPVdERBXQq1cv+Pj44Mknn8SCBQugVCrx3Xff4fTp0/Zumtm0adOwbNkyPPzww3jrrbfQrFkz/Prrr9ixYwcAlFudb+TIkXjzzTexYMEC9OvXDxcvXsQbb7yBxo0bIz8/v9LtkclkePPNN/HYY4/h/vvvx+OPP460tDQsXLiwQsMCAWmo4tWrVzF9+nTs2LED999/Pxo2bIg7d+5g165dWL16NX744Qfz9V7WeHt7Y/78+Xj55ZcxdepUPPjgg0hJScHrr78OjUaDBQsWAJCC5NNPP40HHngAzZs3h0qlwt69e3HmzBlzb85nn32GvXv3YsSIEQgLC0NeXp65VPjgwYMr9JlmzJiBrVu3msvMh4aGmpfZ+jybOnUqli1bhqlTp+Ltt99G8+bNsW3bNvM5YeLp6Ym+ffvi/fffR4MGDRAREYH9+/fj66+/hre3t8W6bdu2BQB88cUX8PDwgEajQePGja0O6bv33nsxdOhQzJ07FxkZGejdu7e5WmCnTp0wZcqUKn2u0ly5cgWbNm0qMb9169aYOnUqPv30U0ybNg3Xrl1Du3bt8Ntvv+Gdd97B8OHDzT+/1157DYmJiRg0aBBCQkKQlpaGDz/80OLat1GjRqFt27bo2rUr/P39cf36dSxfvhzh4eHmypNEVE/Zt54GEZH9lFYtsE2bNlbXP3z4sBgVFSW6urqK/v7+4mOPPSb+8ccfJaqulVYtcMSIESX2Wby6W2nVAou3s7T3iY+PF8eOHSu6u7uLHh4e4rhx48Rt27ZZrRhXnFarFV944QWxUaNGokajETt37ixu2bKlRAU4U7XA999/v8Q+AIgLFiywmPfVV1+JzZs3F1UqldiiRQtx1apVJfZZlvz8fPGbb74RBw4cKPr6+ooKhUL09/cXo6Ojxe+//140GAyiKBYeu40bN1rdz1dffSW2b99eVKlUopeXlzh69Gjxr7/+Mi//559/xOnTp4stW7YU3dzcRHd3d7F9+/bismXLzFURjxw5It5///1ieHi4qFarRT8/P7Ffv37izz//XKHPIoqiqNPpxIYNG1qtXCeK1TvPip9PoiiKiYmJ4rhx4yzOicOHD5fYn2k9Hx8f0cPDQxw2bJj4559/iuHh4eK0adMs9rl8+XKxcePGolwut9iPtZ9rbm6uOHfuXDE8PFxUKpViUFCQ+NRTT4l37961WK+ivyOlAVDqw3ROpqSkiE8++aQYFBQkKhQKMTw8XJw3b56Yl5dn3s8vv/wiRkdHi40aNRJVKpUYEBAgDh8+XDx48KB5naVLl4q9evUSGzRoIKpUKjEsLEycMWOGeO3atXLbSUTOTRDFImM1iIjI6bzzzjt49dVXER8fj5CQEHs3h4iIyGlxWCARkRP55JNPAAAtW7aEXq/H3r178dFHH+Hhhx9msCIiIqphDFdERE7E1dUVy5Ytw7Vr16DVahEWFoa5c+fi1VdftXfTiIiInB6HBRIREREREdkAS7ETERERERHZAMMVERERERGRDTBcERERERER2QALWlhhNBpx8+ZNeHh4QBAEezeHiIiIiIjsRBRFZGZmIjg4GDJZ2X1TDFdW3Lx5E6GhofZuBhERERER1REJCQnl3taE4coKDw8PANIB9PT0tHNriIiIiIjIXjIyMhAaGmrOCGVhuLLCNBTQ09OT4YqIiIiIiCp0uRALWhAREREREdkAwxUREREREZENMFwRERERERHZAK+5IiIiIqrnRFFEfn4+DAaDvZtCZBdKpRJyubza+2G4IiIiIqrHdDodkpKSkJOTY++mENmNIAgICQmBu7t7tfbDcEVERERUTxmNRsTFxUEulyM4OBgqlapCFdGInIkoirh9+zYSExPRvHnzavVgMVwRERER1VM6nQ5GoxGhoaFwdXW1d3OI7Mbf3x/Xrl2DXq+vVrhiQQsiIiKiek4m41dCqt9s1WPL3yQiIiIiIiIbYLgiIiIiIiKyAYYrIiIiIqr3+vfvj+eff77C61+7dg2CIODUqVM11iZyPAxXREREROQwBEEo8zF9+vQq7fenn37Cm2++WeH1Q0NDkZSUhLZt21bp/SqKIc6xsFogERERETmMpKQk8+sNGzbgtddew8WLF83zXFxcLNbX6/VQKpXl7tfX17dS7ZDL5QgMDKzUNuT82HNVx31x4Aru/WA/Vh+Ks3dTiIiIyMmJoogcXb5dHqIoVqiNgYGB5oeXlxcEQTBP5+XlwdvbGz/++CP69+8PjUaDdevWISUlBQ8++CBCQkLg6uqKdu3aYf369Rb7LT4sMCIiAu+88w4effRReHh4ICwsDF988YV5efEepdjYWAiCgD179qBr165wdXVFr169LIIfALz11lsICAiAh4cHHnvsMbz00kvo2LFjlX5eAKDVavHss88iICAAGo0G99xzD44fP25efvfuXUyePBn+/v5wcXFB8+bNsXr1agBSKf6nn34aQUFB0Gg0iIiIwKJFi6rcFmLPVZ2XmZePS7eycPlWlr2bQkRERE4uV29A69d22OW9z70xFK4q23w1nTt3LpYuXYrVq1dDrVYjLy8PXbp0wdy5c+Hp6YmtW7diypQpaNKkCXr06FHqfpYuXYo333wTL7/8MjZt2oSnnnoKffv2RcuWLUvd5pVXXsHSpUvh7++PJ598Eo8++igOHToEAPjuu+/w9ttvY8WKFejduzd++OEHLF26FI0bN67yZ/3Pf/6DmJgYfPPNNwgPD8fixYsxdOhQXL58Gb6+vpg/fz7OnTuHX3/9FQ0aNMDly5eRm5sLAPjoo4/w888/48cff0RYWBgSEhKQkJBQ5bYQw1WdF+oj3dAvPjXHzi0hIiIicgzPP/88xo4dazHvhRdeML9+5plnsH37dmzcuLHMcDV8+HDMnDkTgBTYli1bhtjY2DLD1dtvv41+/foBAF566SWMGDECeXl50Gg0+PjjjzFjxgw88sgjAIDXXnsNO3fuRFZW1f4TPTs7GytXrsSaNWsQHR0NAPjyyy+xa9cufP3113jxxRcRHx+PTp06oWvXrgCkHjmT+Ph4NG/eHPfccw8EQUB4eHiV2kGFGK7quFBfKVwl3s21c0uIiIjI2bko5Tj3xlC7vbetmIKEicFgwLvvvosNGzbgxo0b0Gq10Gq1cHNzK3M/7du3N782DT+8detWhbcJCgoCANy6dQthYWG4ePGiOayZdO/eHXv37q3Q5yruypUr0Ov16N27t3meUqlE9+7dcf78eQDAU089hXHjxuGPP/7AkCFDMGbMGPTq1QsAMH36dNx7772IjIzEsGHDMHLkSAwZMqRKbSEJw1UdF+orXZSZeDcHBqMIucw2d48mIiIiKk4QBJsNzbOn4qFp6dKlWLZsGZYvX4527drBzc0Nzz//PHQ6XZn7KV4IQxAEGI3GCm8jCNL3tqLbmOaZVPRaM2tM21rbp2ledHQ0rl+/jq1bt2L37t0YNGgQZs2ahSVLlqBz586Ii4vDr7/+it27d2PChAkYPHgwNm3aVOU21XcsaFHHBXm5QCEToDeI+Ccjz97NISIiInI4Bw8exOjRo/Hwww+jQ4cOaNKkCS5dulTr7YiMjMSxY8cs5p04caLK+2vWrBlUKhV+++038zy9Xo8TJ06gVatW5nn+/v6YPn061q1bh+XLl1sU5vD09MTEiRPx5ZdfYsOGDYiJiUFqamqV21TfOf5/TTg5uUxAIx8XXE/JQXxqDoK9XcrfiIiIiIjMmjVrhpiYGBw+fBg+Pj744IMPkJycbBFAasMzzzyDxx9/HF27dkWvXr2wYcMGnDlzBk2aNCl32+JVBwGgdevWeOqpp/Diiy/C19cXYWFhWLx4MXJycjBjxgwA0nVdXbp0QZs2baDVavHLL7+YP/eyZcsQFBSEjh07QiaTYePGjQgMDIS3t7dNP3d9wnDlAMJ8XXE9JQcJqTno2cTP3s0hIiIicijz589HXFwchg4dCldXVzzxxBMYM2YM0tPTa7UdkydPxtWrV/HCCy8gLy8PEyZMwPTp00v0ZlkzadKkEvPi4uLw7rvvwmg0YsqUKcjMzETXrl2xY8cO+Pj4AABUKhXmzZuHa9euwcXFBX369MEPP/wAAHB3d8d7772HS5cuQS6Xo1u3bti2bRtkMg5uqypBrM5ATyeVkZEBLy8vpKenw9PT097Nwcubz+L73+Px7MBmmD0k0t7NISIiIieRl5eHuLg4NG7cGBqNxt7NqZfuvfdeBAYG4ttvv7V3U+q1sn4XKpMN2HPlAFiOnYiIiMjx5eTk4LPPPsPQoUMhl8uxfv167N69G7t27bJ308hGGK4cQFhBOfYElmMnIiIicliCIGDbtm146623oNVqERkZiZiYGAwePNjeTSMbYbhyAKZy7Oy5IiIiInJcLi4u2L17t72bQTWIV6s5AFPP1e1MLXJ1Bju3hoiIiIiIrGG4cgBeLkp4qKVOxsS77L0iIiIiIqqLGK4cgCAICDVfd8VwRURERERUFzFcOQjzdVcpDFdERERERHURw5WDYMVAIiIiIqK6jeHKQZiGBbJiIBERERFR3cRw5SDM11wxXBERERHVG/3798fzzz9vno6IiMDy5cvL3EYQBGzZsqXa722r/dQnDFcOItSnMFyJomjn1hARERHZV3JyMp555hk0adIEarUaoaGhGDVqFPbs2WPvpgEARo0aVerNgY8cOQJBEPDHH39Uer/Hjx/HE088Ud3mWVi4cCE6duxYYn5SUhKio6Nt+l7FrVmzBt7e3jX6HrWJNxF2ECE+UkGLbJ0Bd3P08HVT2blFRERERPZx7do19O7dG97e3li8eDHat28PvV6PHTt2YNasWbhw4YLV7fR6PZRKZa20ccaMGRg7diyuX7+O8PBwi2WrVq1Cx44d0blz50rv19/f31ZNLFdgYGCtvZezYM+Vg9Ao5Qj01ADgdVdERERUQ0QR0GXb51GJkTkzZ86EIAg4duwYxo8fjxYtWqBNmzaYPXs2jh49al5PEAR89tlnGD16NNzc3PDWW28BAFauXImmTZtCpVIhMjIS3377rcX+Fy5ciLCwMKjVagQHB+PZZ581L1uxYgWaN28OjUaDhg0bYvz48VbbOHLkSAQEBGDNmjUW83NycrBhwwbMmDEDKSkpePDBBxESEgJXV1e0a9cO69evL/OzFx8WeOnSJfTt2xcajQatW7fGrl27Smwzd+5ctGjRAq6urmjSpAnmz58PvV4PQOo5ev3113H69GkIggBBEMxtLj4s8OzZsxg4cCBcXFzg5+eHJ554AllZWebl06dPx5gxY7BkyRIEBQXBz88Ps2bNMr9XVcTHx2P06NFwd3eHp6cnJkyYgH/++ce8/PTp0xgwYAA8PDzg6emJLl264MSJEwCA69evY9SoUfDx8YGbmxvatGmDbdu2VbktFcGeKwcS6uuC5Iw8xKfmoGOot72bQ0RERM5GnwO8E2yf9375JqByK3e11NRUbN++HW+//Tbc3EquX3yI2YIFC7Bo0SIsW7YMcrkcmzdvxnPPPYfly5dj8ODB+OWXX/DII48gJCQEAwYMwKZNm7Bs2TL88MMPaNOmDZKTk3H69GkAwIkTJ/Dss8/i22+/Ra9evZCamoqDBw9abadCocDUqVOxZs0avPbaaxAEAQCwceNG6HQ6TJ48GTk5OejSpQvmzp0LT09PbN26FVOmTEGTJk3Qo0ePco+F0WjE2LFj0aBBAxw9ehQZGRkW12eZeHh4YM2aNQgODsbZs2fx+OOPw8PDA//5z38wceJE/Pnnn9i+fTt2794NAPDy8iqxj5ycHAwbNgw9e/bE8ePHcevWLTz22GN4+umnLQLkvn37EBQUhH379uHy5cuYOHEiOnbsiMcff7zcz1OcKIoYM2YM3NzcsH//fuTn52PmzJmYOHEiYmNjAQCTJ09Gp06dsHLlSsjlcpw6dcrcOzlr1izodDocOHAAbm5uOHfuHNzd3SvdjspguHIgob6uOH7tLotaEBERUb11+fJliKKIli1bVmj9hx56CI8++qjF9PTp0zFz5kwAMPd2LVmyBAMGDEB8fDwCAwMxePBgKJVKhIWFoXv37gCkXhQ3NzeMHDkSHh4eCA8PR6dOnUp970cffRTvv/8+YmNjMWDAAADSkMCxY8fCx8cHPj4+eOGFF8zrP/PMM9i+fTs2btxYoXC1e/dunD9/HteuXUNISAgA4J133ilxndSrr75qfh0REYE5c+Zgw4YN+M9//gMXFxe4u7tDoVCUOQzwu+++Q25uLtauXWsOtZ988glGjRqF9957Dw0bNgQA+Pj44JNPPoFcLkfLli0xYsQI7Nmzp0rhavfu3Thz5gzi4uIQGhoKAPj222/Rpk0bHD9+HN26dUN8fDxefPFF8/nQvHlz8/bx8fEYN24c2rVrBwBo0qRJpdtQWQxXDqRoUQsiIiIim1O6Sj1I9nrvCjAV9jL1BJWna9euFtPnz58vURCid+/e+PDDDwEADzzwAJYvX44mTZpg2LBhGD58OEaNGgWFQoF7770X4eHh5mXDhg3D/fffD1dXV3z33Xf417/+Zd7nr7/+ij59+qBXr15YtWoVBgwYgCtXruDgwYPYuXMnAMBgMODdd9/Fhg0bcOPGDWi1Wmi1Wqs9ctacP38eYWFh5mAFAFFRUSXW27RpE5YvX47Lly8jKysL+fn58PT0rNB7FH2vDh06WLStd+/eMBqNuHjxojlctWnTBnK53LxOUFAQzp49W6n3KvqeoaGh5mAFAK1bt4a3tzfOnz+Pbt26Yfbs2Xjsscfw7bffYvDgwXjggQfQtGlTAMCzzz6Lp556Cjt37sTgwYMxbtw4tG/fvkptqShec+VACm8kzHBFRERENUAQpKF59nhUMCw1b94cgiDg/PnzFVrfWlApHsxEUTTPCw0NxcWLF/Hpp5/CxcUFM2fORN++faHX6+Hh4YE//vgD69evR1BQEF577TV06NABaWlpuO+++3Dq1CnzwxTqZsyYgZiYGGRkZGD16tUIDw/HoEGDAABLly7FsmXL8J///Ad79+7FqVOnMHToUOh0ugp9NmsVpIt/tqNHj2LSpEmIjo7GL7/8gpMnT+KVV16p8HtYO0ZlvWfxgiGCIMBoNFbqvcp7z6LzFy5ciL/++gsjRozA3r170bp1a2zevBkA8Nhjj+Hq1auYMmUKzp49i65du+Ljjz+uUlsqiuHKgfBGwkRERFTf+fr6YujQofj000+RnZ1dYnlaWlqZ27dq1Qq//fabxbzDhw+jVatW5mkXFxfcd999+OijjxAbG4sjR46Ye18UCgUGDx6MxYsX48yZM7h27Rr27t0LDw8PNGvWzPxwcZEqPU+YMAFyuRzff/89vvnmGzzyyCPmYHDw4EGMHj0aDz/8MDp06IAmTZrg0qVLFT4WrVu3Rnx8PG7eLOxtPHLkiMU6hw4dQnh4OF555RV07doVzZs3x/Xr1y3WUalUMBgM5b7XqVOnLI75oUOHIJPJ0KJFiwq3uTJMny8hIcE879y5c0hPT7f4ebVo0QL//ve/sXPnTowdOxarV682LwsNDcWTTz6Jn376CXPmzMGXX35ZI2014bBAB2LqubqZlod8gxEKObMxERER1T8rVqxAr1690L17d7zxxhto37498vPzsWvXLqxcubLMXq0XX3wREyZMQOfOnTFo0CD897//xU8//WQu5rBmzRoYDAb06NEDrq6u+Pbbb+Hi4oLw8HD88ssvuHr1Kvr27QsfHx9s27YNRqMRkZGRpb6fu7s7Jk6ciJdffhnp6emYPn26eVmzZs0QExODw4cPw8fHBx988AGSk5MtgkNZBg8ejMjISEydOhVLly5FRkYGXnnlFYt1mjVrhvj4ePzwww/o1q0btm7dau7ZMYmIiEBcXBxOnTqFkJAQeHh4QK1WW6wzefJkLFiwANOmTcPChQtx+/ZtPPPMM5gyZYp5SGBVGQwGnDp1ymKeSqXC4MGD0b59e0yePBnLly83F7To168funbtitzcXLz44osYP348GjdujMTERBw/fhzjxo0DADz//POIjo5GixYtcPfuXezdu7fCx7aq+O3cgQR4qKFSyGAwikhKz7N3c4iIiIjsonHjxvjjjz8wYMAAzJkzB23btsW9996LPXv2YOXKlWVuO2bMGHz44Yd4//330aZNG3z++edYvXo1+vfvD0CqNvjll1+id+/eaN++Pfbs2YP//ve/8PPzg7e3N3766ScMHDgQrVq1wmeffYb169ejTZs2Zb7njBkzcPfuXQwePBhhYWHm+fPnz0fnzp0xdOhQ9O/fH4GBgRgzZkyFj4NMJsPmzZuh1WrRvXt3PPbYY3j77bct1hk9ejT+/e9/4+mnn0bHjh1x+PBhzJ8/32KdcePGYdiwYRgwYAD8/f2tloN3dXXFjh07kJqaim7dumH8+PEYNGgQPvnkkwq3tzRZWVno1KmTxWP48OHmUvA+Pj7o27cvBg8ejCZNmmDDhg0AALlcjpSUFEydOhUtWrTAhAkTEB0djddffx2AFNpmzZqFVq1aYdiwYYiMjMSKFSuq3d6yCKK1wZr1XEZGBry8vJCenl7pi/1q2sClsbh6OxvfP9YDvZo1sHdziIiIyIHl5eUhLi4OjRs3hkajsXdziOymrN+FymQD9lw5GFPFQF53RURERERUtzBcORhWDCQiIiIiqpvsGq4OHDiAUaNGITg42DymsiyxsbEQBKHE48KFCxbrpaWlYdasWQgKCoJGo0GrVq2wbdu2GvwktSfMXDEw184tISIiIiKiouxaLTA7OxsdOnTAI488Yq7qUREXL160GO/o7+9vfq3T6XDvvfciICAAmzZtQkhICBISEuDh4WHTtttLqK9U1pPDAomIiIiI6ha7hqvo6GhER0dXeruAgAB4e3tbXbZq1Sqkpqbi8OHD5puYhYeHl7k/092wTTIyMirdptpiutdVIsMVERER2Qjrm1F9Z6vfAYe85qpTp04ICgrCoEGDsG/fPotlP//8M6KiojBr1iw0bNgQbdu2xTvvvFPmjdEWLVoELy8v8yM0NLSmP0KVmcJVSrYO2dp8O7eGiIiIHJnpP6JzcviftlS/6XQ6AFJ59+pwqJsIBwUF4YsvvkCXLl2g1Wrx7bffYtCgQYiNjUXfvn0BAFevXsXevXsxefJkbNu2DZcuXcKsWbOQn5+P1157zep+582bh9mzZ5unMzIy6mzA8tQo4e2qRFqOHgl3c9AysG6ViiciIiLHIZfL4e3tjVu3bgGQ7mUkCIKdW0VUu4xGI27fvg1XV1coFNWLRw4VriIjIy3ugB0VFYWEhAQsWbLEHK6MRiMCAgLwxRdfQC6Xo0uXLrh58ybef//9UsOVWq0ucRfquizUxxVpOemIT2G4IiIiouoJDAwEAHPAIqqPZDIZwsLCqv2fCw4Vrqzp2bMn1q1bZ54OCgqCUqm06NJr1aoVkpOTodPpoFKp7NFMmwrzdcXZG+lIuMuKgURERFQ9giAgKCgIAQEB0Ov19m4OkV2oVCrIZNW/Ysrhw9XJkycRFBRknu7duze+//57GI1G8wH6+++/ERQU5BTBCgBCCioGJrCoBREREdmIXC6v9vUmRPWdXcNVVlYWLl++bJ6Oi4vDqVOn4Ovri7CwMMybNw83btzA2rVrAQDLly9HREQE2rRpA51Oh3Xr1iEmJgYxMTHmfTz11FP4+OOP8dxzz+GZZ57BpUuX8M477+DZZ5+t9c9XU8w3Ema4IiIiIiKqM+wark6cOIEBAwaYp01FJaZNm4Y1a9YgKSkJ8fHx5uU6nQ4vvPACbty4ARcXF7Rp0wZbt27F8OHDzeuEhoZi586d+Pe//4327dujUaNGeO655zB37tza+2A1LNTHdCNhhisiIiIiorpCEHljgxIyMjLg5eWF9PR0i5sV1xXX7mSj/5JYaJQynH9jGKv6EBERERHVkMpkA4e8z1V9F+ztApkA5OmNuJ2lLX8DIiIiIiKqcQxXDkilkCHIy1TUghUDiYiIiIjqAoYrBxXKioFERERERHUKw5WDYlELIiIiIqK6heHKQbEcOxERERFR3cJw5aBCfdlzRURERERUlzBcOShTuEq8y4IWRERERER1AcOVgzIVtLiZngtdvtHOrSEiIiIiIoYrB+XvroZGKYMoAjfT2HtFRERERGRvDFcOShAEVgwkIiIiIqpDGK4cmLli4F2GKyIiIiIie2O4cmCsGEhEREREVHcwXDkwc8XAVF5zRURERERkbwxXDiyMPVdERERERHUGw5UDM5VjZ7giIiIiIrI/hisHZqoWmJ6rR3qu3s6tISIiIiKq3xiuHJibWgE/NxUAIIG9V0REREREdsVw5eDMRS1Yjp2IiIiIyK4Yrhwcy7ETEREREdUNDFcOLqygqEUCy7ETEREREdkVw5WDMxW1YM8VEREREZF9MVw5ONO9rhJ4zRURERERkV0xXDk4c0GL1FwYjaKdW0NEREREVH8xXDm4IC8N5DIBOoMRtzK19m4OEREREVG9xXDl4BRyGRp5S0UteN0VEREREZH9MFw5gVBzxUCGKyIiIiIie2G4cgJhvNcVEREREZHdMVw5gZCCcuzsuSIiIiIish+GKyfAcuxERERERPbHcOUEQjkskIiIiIjI7hiunICp5+qfDC3y9AY7t4aIiIiIqH5iuHICPq5KuKnkAIDEu7l2bg0RERERUf3EcOUEBEEwDw3kdVdERERERPbBcOUkzOGK110REREREdkFw5WTCGO4IiIiIiKyK4YrJ8EbCRMRERER2RfDlZMI9XUBACSksqAFEREREZE9MFw5iaLDAkVRtHNriIiIiIjqH4YrJxHiI4WrTG0+0nL0dm4NEREREVH9w3DlJDRKOQI81ABYjp2IiIiIyB4YrpxIKItaEBERERHZDcOVEym87opFLYiIiIiIahvDlRMJ9ZEqBrLnioiIiIio9jFcORHTsMBEXnNFRERERFTrGK6cCK+5IiIiIiKyH4YrJ2K65urG3VwYjLzXFRERERFRbWK4ciINPTVQygXkG0UkpbOoBRERERFRbWK4ciJymWC+mTArBhIRERER1S6GKycTai7HzuuuiIiIiIhqE8OVkzGVY09gxUAiIiIiolrFcOVkwlgxkIiIiIjILhiunAzLsRMRERER2QfDlZMJ82VBCyIiIiIie2C4cjKhBdUC72RpkaPLt3NriIiIiIjqD4YrJ+PlqoSnRgEASLzL3isiIiIiotrCcOWEzNddpfC6KyIiIiKi2mLXcHXgwAGMGjUKwcHBEAQBW7ZsKXP92NhYCIJQ4nHhwgWr6//www8QBAFjxoyxfePrMPN1VyzHTkRERERUaxT2fPPs7Gx06NABjzzyCMaNG1fh7S5evAhPT0/ztL+/f4l1rl+/jhdeeAF9+vSxSVsdCSsGEhERERHVPruGq+joaERHR1d6u4CAAHh7e5e63GAwYPLkyXj99ddx8OBBpKWlVb2RDiiUFQOJiIiIiGqdQ15z1alTJwQFBWHQoEHYt29fieVvvPEG/P39MWPGjArtT6vVIiMjw+LhyArLsbPnioiIiIiotjhUuAoKCsIXX3yBmJgY/PTTT4iMjMSgQYNw4MAB8zqHDh3C119/jS+//LLC+120aBG8vLzMj9DQ0Jpofq0J9XEBIF1zJYqinVtDRERERFQ/2HVYYGVFRkYiMjLSPB0VFYWEhAQsWbIEffv2RWZmJh5++GF8+eWXaNCgQYX3O2/ePMyePds8nZGR4dABq5GPCwQByNEZkJKtQwN3tb2bRERERETk9BwqXFnTs2dPrFu3DgBw5coVXLt2DaNGjTIvNxqNAACFQoGLFy+iadOmJfahVquhVjtPAFEr5Aj01CApPQ8JqTkMV0REREREtcDhw9XJkycRFBQEAGjZsiXOnj1rsfzVV19FZmYmPvzwQ4fujaqsUF9XJKXnIT41B53CfOzdHCIiIiIip2fXcJWVlYXLly+bp+Pi4nDq1Cn4+voiLCwM8+bNw40bN7B27VoAwPLlyxEREYE2bdpAp9Nh3bp1iImJQUxMDABAo9Ggbdu2Fu9hqipYfL6zC/VxxbG4VBa1ICIiIiKqJXYNVydOnMCAAQPM06brnqZNm4Y1a9YgKSkJ8fHx5uU6nQ4vvPACbty4ARcXF7Rp0wZbt27F8OHDa73tdV0Yy7ETEREREdUqQWQ5uRIyMjLg5eWF9PR0i5sVO5Kf/kjE7B9PI6qJH9Y/0dPezSEiIiIickiVyQYOVYqdKs7cc3WXwwKJiIiIiGoDw5WTCi0IVzfTcqE3GO3cGiIiIiIi58dw5aT83dVQK2QwikBSWp69m0NERERE5PQYrpyUTCYgxMcFABDPioFERERERDWO4cqJ8borIiIiIqLaw3DlxEzhij1XREREREQ1j+HKiYWa73XFcEVEREREVNMYrpwYwxURERERUe1huHJioT4cFkhEREREVFsYrpxYqK9ULfBujh6ZeXo7t4aIiIiIyLkxXDkxD40SPq5KAEBCaq6dW0NERERE5NwYrpwcy7ETEREREdUOhisnF8KiFkREREREtYLhysmFMVwREREREdUKhisnx4qBRERERES1g+HKyRVec8WCFkRERERENYnhyskVHRYoiqKdW0NERERE5LwYrpxckLcGMgHQ5htxO1Nr7+YQERERETkthisnp5TLEOwt3UyY110REREREdUchqt6wFTUgve6IiIiIiKqOQxX9YDpuqv4FBa1ICIiIiKqKQxX9UCoL4cFEhERERHVNIareiDUl8MCiYiIiIhqGsNVPRBapBw7ERERERHVDIaresB0zVVyRh60+QY7t4aIiIiIyDkxXNUDfm4quCjlEEXgxl0WtSAiIiIiqgkMV/WAIAjm3qsEhisiIiIiohrBcFVPmK67YsVAIiIiIqKawXBVT5jKsScyXBERERER1QiGq3oijD1XREREREQ1iuGqngj14b2uiIiIiIhqEsNVPRHmV9BzlcJwRURERERUExiu6okQH+maq4y8fKTn6O3cGiIiIiIi58NwVU+4qhRo4K4GwKGBREREREQ1geGqHjFVDGRRCyIiIiIi22O4qkfMNxJmuCIiIiIisjmGq3rEVDGQPVdERERERLbHcFWPmHuu7ubauSVERERERM6H4aoeCSm45orDAomIiIiIbI/hqh4x9VzduJsLg1G0c2uIiIiIiJwLw1U9EuTlAoVMgM5gxD8ZefZuDhERERGRU2G4qkfkMgGNfDg0kIiIiIioJjBc1TOmoYGsGEhEREREZFsMV/VMiA8rBhIRERER1QSGq3qGNxImIiIiIqoZDFf1TGhBOXYOCyQiIiIisi2Gq3qGPVdERERERDWD4aqeCS245upWphZ5eoOdW0NERERE5DwYruoZb1clPNQKAEDiXfZeERERERHZCsNVPSMIAkJYjp2IiIiIyOYYruqhMF/TjYRZjp2IiIiIyFYYruoh3kiYiIiIiMj2GK7qoVBWDCQiIiIisjmGq3oolD1XREREREQ2x3BVD5nKsSfezYUoinZuDRERERGRc6hSuEpISEBiYqJ5+tixY3j++efxxRdf2KxhVHNCfKSCFlnafNzN0du5NUREREREzqFK4eqhhx7Cvn37AADJycm49957cezYMbz88st44403bNpAsj2NUo6GnmoAHBpIRERERGQrVQpXf/75J7p37w4A+PHHH9G2bVscPnwY33//PdasWVPh/Rw4cACjRo1CcHAwBEHAli1bylw/NjYWgiCUeFy4cMG8zpdffok+ffrAx8cHPj4+GDx4MI4dO1aVj+nUwljUgoiIiIjIpqoUrvR6PdRqqedj9+7duO+++wAALVu2RFJSUoX3k52djQ4dOuCTTz6p1PtfvHgRSUlJ5kfz5s3Ny2JjY/Hggw9i3759OHLkCMLCwjBkyBDcuHGjUu/h7EzXXbHnioiIiIjINhRV2ahNmzb47LPPMGLECOzatQtvvvkmAODmzZvw8/Or8H6io6MRHR1d6fcPCAiAt7e31WXfffedxfSXX36JTZs2Yc+ePZg6darVbbRaLbRarXk6IyOj0m1yNKaKgYl3Ga6IiIiIiGyhSj1X7733Hj7//HP0798fDz74IDp06AAA+Pnnn83DBWtSp06dEBQUhEGDBpmv/SpNTk4O9Ho9fH19S11n0aJF8PLyMj9CQ0Nt3eQ6h+XYiYiIiIhsq0o9V/3798edO3eQkZEBHx8f8/wnnngCrq6uNmtccUFBQfjiiy/QpUsXaLVafPvttxg0aBBiY2PRt29fq9u89NJLaNSoEQYPHlzqfufNm4fZs2ebpzMyMpw+YBVec5Vr55YQERERETmHKoWr3Fzp/kimYHX9+nVs3rwZrVq1wtChQ23awKIiIyMRGRlpno6KikJCQgKWLFliNVwtXrwY69evR2xsLDQaTan7VavV5mvI6gtTuLqRlot8gxEKOW95RkRERERUHVX6Rj169GisXbsWAJCWloYePXpg6dKlGDNmDFauXGnTBpanZ8+euHTpUon5S5YswTvvvIOdO3eiffv2tdomRxDgoYZKIYPBKCIpPc/ezSEiIiIicnhVCld//PEH+vTpAwDYtGkTGjZsiOvXr2Pt2rX46KOPbNrA8pw8eRJBQUEW895//328+eab2L59O7p27Vqr7XEUMplgvpkwy7ETEREREVVflYYF5uTkwMPDAwCwc+dOjB07FjKZDD179sT169crvJ+srCxcvnzZPB0XF4dTp07B19cXYWFhmDdvHm7cuGHuJVu+fDkiIiLQpk0b6HQ6rFu3DjExMYiJiTHvY/HixZg/fz6+//57REREIDk5GQDg7u4Od3f3qnxcpxXq44qrt7ORwIqBRERERETVVqWeq2bNmmHLli1ISEjAjh07MGTIEADArVu34OnpWeH9nDhxAp06dUKnTp0AALNnz0anTp3w2muvAQCSkpIQHx9vXl+n0+GFF15A+/bt0adPH/z222/YunUrxo4da15nxYoV0Ol0GD9+PIKCgsyPJUuWVOWjOrUwVgwkIiIiIrIZQRRFsbIbbdq0CQ899BAMBgMGDhyIXbt2AZBKmh84cAC//vqrzRtamzIyMuDl5YX09PRKhUVH88WBK3hn2wXc1yEYHz3Yyd7NISIiIiKqcyqTDao0LHD8+PG45557kJSUZL7HFQAMGjQI999/f1V2SXbAnisiIiIiItupUrgCgMDAQAQGBiIxMRGCIKBRo0a1cgNhsp0QH9O9rhiuiIiIiIiqq0rXXBmNRrzxxhvw8vJCeHg4wsLC4O3tjTfffBNGo9HWbaQaEuYnhauUbB2ytfl2bg0RERERkWOrUs/VK6+8gq+//hrvvvsuevfuDVEUcejQISxcuBB5eXl4++23bd1OqgGeGiW8XJRIz9Uj4W4OWgY67/VlREREREQ1rUrh6ptvvsFXX32F++67zzyvQ4cOaNSoEWbOnMlw5UDCfF1x9kY6ElJzGa6IiIiIiKqhSsMCU1NT0bJlyxLzW7ZsidTU1Go3impPqK90I2EWtSAiIiIiqp4qhasOHTrgk08+KTH/k08+Qfv27avdKKo9ob4sakFEREREZAtVGha4ePFijBgxArt370ZUVBQEQcDhw4eRkJCAbdu22bqNVIPCGK6IiIiIiGyiSj1X/fr1w99//437778faWlpSE1NxdixY/HXX39h9erVtm4j1aBQUzn2uwxXRERERETVIYiiKNpqZ6dPn0bnzp1hMBhstUu7qMxdmB3dtTvZ6L8kFi5KOc69MRSCINi7SUREREREdUZlskGVeq7IeQR7u0AQgFy9AXeydPZuDhERERGRw2K4qudUChmCvVgxkIiIiIiouhiuCCE+UrhK5HVXRERERERVVqlqgWPHji1zeVpaWnXaQnYS5uuK3+NSEZ/CcEVEREREVFWVCldeXl7lLp86dWq1GkS1z3SvKw4LJCIiIiKqukqFK5ZZd07me11xWCARERERUZXxmitCqK90zVVCaq6dW0JERERE5LgYrsg8LDApPRe6fKOdW0NERERE5JgYrgj+7mpolDIYReBmGnuviIiIiIiqguGKIAgCQn143RURERERUXUwXBGAwqIWrBhIRERERFQ1DFcEoPC6Kxa1ICIiIiKqGoYrAlA0XLHnioiIiIioKhiuCAAQ6lNQjp3XXBERERERVQnDFQEAwvx4zRURERERUXUwXBEAmKsFpuXokZGnt3NriIiIiIgcD8MVAQDc1Ar4uakA8LorIiIiIqKqYLgisxAWtSAiIiIiqjKGKzILYzl2IiIiIqIqY7giszBfqWIgi1oQEREREVUewxWZmYpasBw7EREREVHlMVyRmWlYIHuuiIiIiIgqj+GKzEILwlXi3VwYjaKdW0NERERE5FgYrsgsyEsDuUyALt+IW5laezeHiIiIiMihMFyRmUIuQ7C3BgCvuyIiIiIiqiyGK7Jgvu4qheGKiIiIiKgyGK7IAisGEhERERFVDcMVWQhlxUAiIiIioiphuCILpnCVwHBFRERERFQpDFdkIcwcrnLt3BIiIiIiIsfCcEUWQn1cAADJGXnI0xvs3BoiIiIiIsfBcEUWfN1UcFPJAQA30th7RURERERUUQxXZEEQBBa1ICIiIiKqAoYrKsEUrhIZroiIiIiIKozhikoIY88VEREREVGlMVxRCaaiFqwYSERERERUcQxXVEKYH3uuiIiIiIgqi+GKSgj1KbyRsCiKdm4NEREREZFjYLiiEkIKwlWmNh/puXo7t4aIiIiIyDEwXFEJLio5/D3UADg0kIiIiIioohiuyCpTxUAWtSAiIiIiqhiGK7LKVDGQPVdERERERBXDcEVWmXuu7jJcERERERFVBMMVWRXqW1gxkIiIiIiIysdwRVYxXBERERERVQ7DlSMwGmv9LU3DAm+k5cJg5L2uiIiIiIjKY9dwdeDAAYwaNQrBwcEQBAFbtmwpc/3Y2FgIglDiceHCBYv1YmJi0Lp1a6jVarRu3RqbN2+uwU9Rw5JOA5/1BpL/rNW3beipgVIuQG8QkZyRV6vvTURERETkiOwarrKzs9GhQwd88sknldru4sWLSEpKMj+aN29uXnbkyBFMnDgRU6ZMwenTpzFlyhRMmDABv//+u62bXzti3wNunQN+nArkZdTa28plgvlmwvEpHBpIRERERFQehT3fPDo6GtHR0ZXeLiAgAN7e3laXLV++HPfeey/mzZsHAJg3bx7279+P5cuXY/369dVprn3c9zHw+Skg9Qrw89PAA98AglArbx3i44K4O9lIuJuDKPjVynsSERERETkqh7zmqlOnTggKCsKgQYOwb98+i2VHjhzBkCFDLOYNHToUhw8fLnV/Wq0WGRkZFo86w81PClQyJXDu/4DfP6u1tw5jUQsiIiIiogpzqHAVFBSEL774AjExMfjpp58QGRmJQYMG4cCBA+Z1kpOT0bBhQ4vtGjZsiOTk5FL3u2jRInh5eZkfoaGhNfYZqiS0GzD0ben1zleB+NoZ4siKgUREREREFWfXYYGVFRkZicjISPN0VFQUEhISsGTJEvTt29c8Xyg2bE4UxRLzipo3bx5mz55tns7IyKh7Aav7E0D8EeCvzcDG6cCTBwG3BjX6lqaeq3iGKyIiIiKicjlUz5U1PXv2xKVLl8zTgYGBJXqpbt26VaI3qyi1Wg1PT0+LR50jCNL1V37NgcybQMxjgNFQo28ZaipokZpbo+9DREREROQMHD5cnTx5EkFBQebpqKgo7Nq1y2KdnTt3olevXrXdNNtTewAT1gIKF+DqPmD/4hp9O1PP1Z0sLXJ1NRvkiIiIiIgcnV2HBWZlZeHy5cvm6bi4OJw6dQq+vr4ICwvDvHnzcOPGDaxduxaAVAkwIiICbdq0gU6nw7p16xATE4OYmBjzPp577jn07dsX7733HkaPHo3/+7//w+7du/Hbb7/V+uerEQ1bA6OWA5v/Bex/T7oeq9ngGnkrL1clPDUKZOTlI+FuDlo09KiR9yEiIiIicgZ27bk6ceIEOnXqhE6dOgEAZs+ejU6dOuG1114DACQlJSE+Pt68vk6nwwsvvID27dujT58++O2337B161aMHTvWvE6vXr3www8/YPXq1Wjfvj3WrFmDDRs2oEePHrX74WpSh0lAl+kARCDmcSA9scbeikUtiIiIiIgqRhBFUbR3I+qajIwMeHl5IT09vW5efwUA+jzg63uB5DNASDdg+jZAobL52zy17n/49c9kLBjVGo/0bmzz/RMRERER1WWVyQYOf81VvaXUSNdfqb2AxOPArtdq5G0Ke65Y1IKIiIiIqCwMV47MtzFwf8FNhX9fKZVpt7FQlmMnIiIiIqoQhitH13I40Ps56fX/PQ3cuVT2+pUU6uMCAEi8y3BFRERERFQWhitnMPA1ILw3oMsCfpwK6GwXhIreSJiX5xERERERlY7hyhnIFcD4VYBbAHDrHLB1NmCjINTIxwWCAOToDEjN1tlkn0REREREzojhyll4BEoBS5ABp9cDf3xjk92qFXIEemoA8LorIiIiIqKyMFw5k8Z9gIHzpdfb/gPcPGWT3Yb6sKgFEREREVF5GK6cTe/ngRbDAINWuv4q9261d2mqGJh4l+XYiYiIiIhKw3DlbGQyYMxKwDsMSLsObJlZ7euvQn2lioHxKey5IiIiIiIqDcOVM3L1BR74BpCrgIvbgMMfVWt3poqBCSzHTkRERERUKoYrZ9WoMzDsXen17teBa4eqvKsw3kiYiIiIiKhcDFfOrOujQLsJgGgANj0CZP5Tpd2YrrlKSs+D3mC0ZQuJiIiIiJwGw5UzEwRg1HLAvxWQ9Q8QMwMw5Fd6N/7uaqgVMhiMIpLS8mzfTiIiIiIiJ8Bw5exUbsCEtYDSDbh2EIh9p9K7kMkEhPhIRS143RURERERkXUMV/WBfwvgvoKiFgeXAhe3V3oXvO6KiIiIiKhsDFf1RbvxQPcnpNebnwDuXqvU5qbrrhIYroiIiIiIrGK4qk+GvAU06gLkpQM/TgPytRXelD1XRERERERlY7iqTxRq4IE1gIsPkHQK2D6vwpuG+JjudZVbM20jIiIiInJwDFf1jXcYMPZL6fWJr4EzP1ZoszAOCyQiIiIiKhPDVX3U/F6g74vS6/8+B9y6UO4mob5StcDUbB2ytJUv505ERERE5OwYruqr/vOAxn0BfQ7w4xRAm1Xm6h4aJXxclQDYe0VEREREZA3DVX0lkwPjVgEeQcCdv4H/PguIYpmbsKgFEREREVHpGK7qM3d/qcCFIAf+jAGOf1Xm6iG87oqIiIiIqFQMV/VdWE/g3jek19vnAYn/K31VhisiIiIiolIxXBEQNQtoORIw6oGN04CcVKurhRaUYz927S7uZutqs4VERERERHUewxUBggCMWQH4NAbSE4CfngCMxhKrRTX1g0ouw/mkDAxZfgC7z/1jh8YSEREREdVNDFck0XgBE9YCCg1weRfw29ISqzRu4IZNT0WhWYA7bmdq8djaE3hx42lk5Ont0GAiIiIiorqF4YoKBbUHhi+RXu97B7gaW2KV9iHe+OWZe/BE3yYQBGDj/xIxbNkB/HbpTu22lYiIiIiojmG4IkudpwAdHwZEIxDzGJBxs8QqGqUcLw9vhR//FYVwP1fcTM/Dw1//jvlb/kSOjjcYJiIiIqL6ieGKShr+PtCwLZB9G9j0KGCwPuyvW4Qvfn2uD6ZGhQMAvj16HdEfHsTxa9YLYhAREREROTOGKypJ5Spdf6X2BOKPAHteL3VVV5UCb4xui3UzeiDYS4PrKTmY8PkRvLPtPPL0hlpsNBERERGRfTFckXV+TYHRn0qvD38MnP9vmavf07wBtv+7Lx7oEgJRBL44cBUjP/4NZxLTar6tRERERER1AMMVla71fUDU09LrLTOB1Ktlru6pUeL9Bzrg62ld4e+hxuVbWbh/xWF8sPMidPklS7sTERERETkThisq2+CFQGgPQJsB/DgV0OeWu8mgVg2x8/m+GNUhGAajiI/2XsaYTw/hQnJGzbeXiIiIiMhOGK6obHIl8MAawLUBkHwW+PU/FdrMx02Fjx/shE8e6gQfVyXOJWVg1Me/YUXsZeQb2ItFRERERM6H4YrK5xkMjPsKgAD8sRb4bRlgqFjJ9ZHtg7Hj330xuFVD6A0iFm+/iAc+P4Krt7Nqts1ERERERLWM4YoqpukAYMDL0uvdC4GVUcD5XwBRLHfTAA8NvpzaBUse6AAPtQIn49Mw/KODWPVbHIzG8rcnIiIiInIEgihW4NtxPZORkQEvLy+kp6fD09PT3s2pO4xG4NgXwP73gNyCe1mF9gDufQMI61mhXdxMy8XcmDM4eOkOAKBnE1+8P74DQn1da6rVRERERERVVplswHBlBcNVOfLSgUMfAkdWAPkFBS4iRwCDFwD+keVuLooivvs9Hu9sO48cnQFuKjleHdkak7qFQhCEGm48EREREVHFMVxVE8NVBWXcBGIXASfXAaIREGRApylA/3mAZ1C5m19PycaLG8/g2DWpF6x/pD/eHdsegV6amm45EREREVGFMFxVE8NVJd2+COx+Hbi4VZpWuABRM4HezwEarzI3NRhFrD4Uh8U7pHtheWoUeGN0W4zuGMxeLCIiIiKyO4aramK4qqLrR4DdC4CE36VpF1+g74tAtxmAQl3mppdvZWLOj6dxOjEdADCsTSDeur8tGriXvR0RERERUU1iuKomhqtqEEXgwlapomDKJWmedzgwcD7QdhwgK71AZb7BiM/2X8GHey5BbxDh56bC2/e3xbC25Q8xJCIiIiKqCQxX1cRwZQOGfODkt0Dsu0BWsjQvsD1w7+tA04FlbvrXzXTM+fE0LiRnAgDGdAzG6/e1hZersqZbTURERERkgeGqmhiubEiXDRxdAfz2IaCTwhKaDJBCVlCHUjfT5hvw0Z5LWBl7BUYRaOipxrvj2mNAZEAtNZyciigCV/cBx78G8rVSVcuAVoB/K8C/BaD2sHcLCQCybkv/KRN/FGgxBOjyCCCT27tVRERUzzFcVRPDVQ3IvgMcWAIc/wow6qV57R4ABr4K+ESUutnJ+LuYs/E0rt7OBgA82D0Ur4xoDXe1ohYaTQ7PaADO/wz8tgxIOl36el6hgH/LIqGr4DVDV80TReD6YeDE18C5nwv/PgBAUEdgxAdASBe7NY+IiIjhqpoYrmpQahyw723g7EZpWq4Cuj0G9HkBcPOzukme3oD3d1zEqkNxEEUgxMcF74/vgKim1tcngj4POL0eOPwRkHpVmqd0BTpPAxo0lypc3j4vPWf9U/p+vEKlkOXfkqHL1vLSgdMbgBOrpJ+FSaOuQOO+Ui+jNh2AAHSeCgxeCLj62qu1RERUjzFcVRPDVS24eUqqLHg1VppWewL3PA/0eApQuVrd5OjVFLy46TQSUqUbF0/vFYG5w1rCRcVhQ1QgL0P6sn50RWFocvEBuv8L6P6E9QCfkwrcviA9bl0ofF1W6PIMAQJaFoQtU/Bi6KqQm6ekXqqzmwB9jjRP6Sr1ZHebUThcOOs2sOs14PT30rSLrxSwOk0pszAOERGRrTFcVRPDVS26vEcKWclnpWmPIOkmxB0nA/KSQ/+ytPl4Z9t5fP97PACgkbcLnuzXBA90DYVGyZBVb2XdAo6uLNLbAcCzEdDrGenLuNq98vvMSbXs4bp1vmqhq0ELQFPP/47ocoC/fpKC743/Fc73bwl0nQF0mFj6PfGuHwG2zgFu/SVNh3QDRiwt85pNIiIiW2K4qiaGq1pmNAJ/bgL2vgmkSaEJDSKBwQuAyOGAlZsJ7//7Nl6KOYOk9DxpdXc1ZtzTGA/3DIOHhlUF643Uq8Dhj4GT3wEGrTSvQaTUC9p2PKBQ2f49qxq6LK7nKhhe6Oyh684lKVCd+k4aBggAMiXQerTUSxUWZfX3uwRDPnDsc2DfIqkwjiCThhMPeAVw8a7Rj0BERMRwVU0MV3aSr5V6Hg68D+SmSvNCewL3vgGE9Sixep7egB9PJODz/VdxI00aKuipUWBarwg80rsxfN1q4Is11Q1JZ4BDy4G/NgOiUZoX0g24599Ai2j7DBszhy7TEEPTNV3JpW/jHQ6E9wbCe0kP3yYVCxt1mUEPXPhFClVxBwrne4dJ1f86TQHc/au274wkYOer0n/GAICbP3Dvm0CHSY5/3IiIqM5iuKomhis7y0sHflsuDfPKl0ITWo4EBi2QymYXozcY8X+nbmJl7GVcKagq6KKUY1L3UDzepwmCvV1qsfG1SBSlQJqfJz0btIXTEKSeEbkT9eKJInDtN6ny35U9hfOb3SuFqvBedfMLdk4qcOfvwh4u07Vd1kKXe2Bh0ArvLfVwOcr1RemJwP/WAH+sLezFE2RA86FSL1XTQbb7LFf3A9tekI4rAIT1AkYsARq2sc3+iYiIimC4qiaGqzoi4yYQuwg4uU7qnRDkQOcp0jVZHoElVjcaRew8l4xP913B2RvSECSlXMDYTiF4sn9TNG7gZtv2iSJg0En38tLnAPrcwqBjfi4l/BRflp8n7ctie13Zyw26stuncgfCegIR9wARfaVrVKxcx1bnGY3AxW1SqLpxQponyIA2Y6Xhf4Ht7Nq8Ksu9K11/dP2w9Ljxv5I/UxcfKTiYAldg+7r1MzQapaB7/Gvg0o7CXkS3AKnCX5fpgHdozbx3vg44+imwf7H0+yfIgZ5PAf1fYmERIiKyKYaramK4qmNuXQD2vC59wQakymI9ZwK9n7N6zYooijh46Q4+3XcZv8elQoAR7oIWI1t549Fu/mjuI5MusNdlSV/KSn2dXRicSrzOAfTZgDG/lg9GaQRAoZGuMVJopFLkpsIOJioPIDwKiOgDNO4jfVGvyzdozdcBZ38EDn1Y2EOh0ACdHgaingZ8G9u3fbamzy0Stg4BCccKq+mZqNyB0B5ARG+pZyu4E6BQ135bs+9IN/s9sRpIu144P6KP1EvVcmTt9ZqmJQA7XpbuZwZIRXGGvAW0HVc3ezKJiMjhMFxVE8NVHXX9iFSaOfGYNO3qJ11fk59bGHaKBh9dNozabMgMeTXfNrkKULoUBBx14bNcXWyeynJariq5TYntS1lWdHu50vKLpNEoVVe79hsQdxC4/lthQQETtZfUG9K4j9S71bBd3RiCps0C/vgGOPIpkHFDmqf2Aro/BvR4EnAPsG/7aotBL934+PqhgsB1pGRgVmika81MPVsh3QCVjXtoTUQRiD8i9VKd/7mwl03jBXR4COj6qNVhu7Xm0m7g1xcL72vWuC8wfKl920RERE6B4aqaGK7qMFGULpbf/TqQcqlSmxohIEdUIxdqZIsaQOUKH28feHp6QVC5SV9Kla7Sc7mv3aX7cZnm1/Vrm4wG4J8/paB17aD0ZV2bYbmOxlvqDWncR+qBCGhdu2ErO0WqCPf750BemjTPvSEQNUsqhODslfXKYzQA//xV2LN1/TCQc8dyHZlC6s0yXbMV2qP61fRKu9lvcGepl6rN2FLvTVfr9HnSjaMPLpWGzsqUQK+ngb4v1lzoJCIip+cw4erAgQN4//338b///Q9JSUnYvHkzxowZU6FtDx06hH79+qFt27Y4deqUxbLly5dj5cqViI+PR4MGDTB+/HgsWrQIGo2mQvtmuHIAhnzpvjl3rxeGnvICkdIF11Jy8PmBK9j0v0ToDdKp3ybYE7MGNMPQNoGQy+rJMCKjQeoVuXZQ6t26fkQqcV2Ui680/Cyir9SzFdCqZoZZpcUDhz+RCiGYCpj4NgV6Pwu0nwQoK/Z7W++IolTq3Nyzdaiwp89MAALbFlYkDOtV8Up9SaelXqqzm6SeYABQuADtxkuhKriTTT+OTaXGAdtfAv7eLk17hgDDFgGtRnGoIBERVZrDhKtff/0Vhw4dQufOnTFu3LgKh6v09HR07twZzZo1wz///GMRrr777jvMmDEDq1atQq9evfD3339j+vTpmDhxIpYtW1ahdjFcOb+k9Fx8dTAO3/8ej1y9AQDQxN8NT/ZrijEdG0GlqAPD42qTIR9IOiWFrbiDQPzRwi/UJq4NCopj3CMNuWrQonpfVP85J11PdXYjIEo/AwR1lCr/tRpVt68Hq4tEUQqqRXu2Uq+UXK9Bi8KerfBegFdI4TJ9LvCn6Wa/J4psEykFqvYTHeu+Uhe2Ab/OBdIL7p/XbDAQvRjwa2rfdhERkUNxmHBVlCAIFQ5XkyZNQvPmzSGXy7FlyxaLcPX000/j/Pnz2LOnsFTznDlzcOzYMRw8eLBCbWG4qj9Ss3VYc/ga1hyKQ0aeVJwi2EuDJ/o2wcRuYXBR1dMv+AY9cPOkdJ+iaweB+N8Le5VM3AIKglYfqXfLr2nFwlb8UanU/t+/Fs5r3E8KVU36s2fBljKTC6sRXj8sXYdXnHeYFLTUHsCZHwuHZMqUUsjtNkNa7qg/F12ONEzw8EfSdWJytVRl8p5/S9dJEhERlcOpw9Xq1auxYsUKHDlyBG+99VaJcPXDDz/gySefxM6dO9G9e3dcvXoVI0aMwLRp0/DSSy9Z3adWq4VWqzVPZ2RkIDQ0lOGqHsnM0+P73+Px5cE43MmSzgU/NxUevacxpkSFw1NTx6+pqmn5OqmS3bWCa7YSjhXcT6sIj6DCnq2IPpY3xBVF4NJOqZx6/JGCDQSg9X1A7+eBRp1r89PUXzmp0vE39W4lnS4sn27iFQZ0nV5ws18nKh5y57J0b6yr+6Rp73CpFytymH3bRUREdZ7ThqtLly7hnnvuwcGDB9GiRQssXLiwRLgCgI8//hhz5syBKIrIz8/HU089hRUrVpS634ULF+L1118vMZ/hqv7J0xuw8X+J+Hz/FSTelXpqPNQKTIkKx6P3NEYDdzuUva6L9HnSsDFTNcLEYyXv0eTZqOBardZSj4ip10SmBDo+CPR6DmjQrPbbToW0mUDC71LYyvxHCrvNBjvvkExRBM79H7B9HpB5U5oXORwY9i7gE27fthERUZ3llOHKYDCgZ8+emDFjBp588kkAsBquYmNjMWnSJLz11lvo0aMHLl++jOeeew6PP/445s+fb3Xf7Lmi4vQGI345cxMr9l3BpVtZAAC1QoYHu4fh8b5N0Mibw4ks6HOBxOOF1QgTTwBGveU6Kneg6yPSPco8g+3TTiJAKve//z3g6ArpXnUKF6DvHKDXs/a5bxgREdVpThmu0tLS4OPjA7m88H9UjUYjRFGEXC7Hzp07MXDgQPTp0wc9e/bE+++/b15v3bp1eOKJJ5CVlQVZBUpL85orMjEaRew6/w9W7LuM04nSPYYUMgFjOjXCk/2aolmAu51bWEfpcqQekWsHgeSzQGh3oNtjgIuPvVtGVOjWeWDrC9J94ACpSuXw94Fmg+zbLiIiqlMqkw0UtdSmavP09MTZs2ct5q1YsQJ79+7Fpk2b0LhxYwBATk5OiQAll8shiiLqSI4kByKTCRjaJhBDWjfE4Ssp+HTfZRy+koJN/0tEzB+JiG4biJn9m6FtIy97N7VuUbkCTQdID6K6KqAVMP0XqWLljlek6orrxgKtRwNDFwFejezdQiJL+lwg927BI63I64JHXvF5adKoAb8m0n8e+DWVnn2bAB6BjluohqgOs2u4ysrKwuXLl83TcXFxOHXqFHx9fREWFoZ58+bhxo0bWLt2LWQyGdq2bWuxfUBAADQajcX8UaNG4YMPPkCnTp3MwwLnz5+P++67z6LXi6gyBEFA72YN0LtZA/wRfxcr9l3B7vP/YNvZZGw7m4y+LfzxSK8IRAZ6oKGnpv7cL4vI0QkC0H4C0GIosO8d4NgX0nVZl3YD/edKw1jr+k3CybEYjdJN3EsNRWmlB6fihYQqylqlUKWbFLKsBS/3AAYvoiqy67DA2NhYDBhQ8n+2p02bhjVr1mD69Om4du0aYmNjrW5v7Zqr/Px8vP322/j2229x48YN+Pv7Y9SoUXj77bfh7e1doXZxWCBVxMXkTKyMvYyfT9+EschvkUouQ4iPC0J9XRFW8DC/9nOFu9phOoyJ6p/ks8DWOdKwVgDwbwm0HAlAlCorikbpJtxikWmrj/KWV2QdK8sVaml4rYu3dKNvFx/p4VrktWm+0oVfkCtLFKVbURi00nO+Vnqdr5OK9phfl7ZcJ83LSy+9NykvvWSVzsoQ5EV+1t5FXhc8NN6Wy/PSgZQrUs9syhUg9ap0TzzT/QWtUXkAvo0LA5dfQejybQq4NeB5RfWOQ15zVZcwXFFlXE/JxhcHruK3y3dw424u8o1l/0r5uqmKBC8Xi/AV5OXCXi8iezMagdPfA7teA3JS7N2aqpOri4Uun7LDmOmhcrVPe03BJj9Xqkiqz5F6avS5FXvO1xaGG1NAMs0z6ApDkbWgVHRebVG6FgtE3sV+TsWnC9ZTe1Q/3OTrpIBlDlxFgld6QtnhT+1Z0ONVpKfL9NrVl8GLnBLDVTUxXFFVGYwiktJzEZ+ag4TUHMSn5iA+tXA6NVtX5vZKuYBG3pa9XqYer1BfV95vi6g25aQCx78Csu8AgqzgIRR5XdqjvHUquQ+ZXHqGIIWI3NTC4WM5qcWGjxVMG/Or/rkVmmLBy9t6IFO6FoSagiCkzysMRmU+l7GsOj06NUGQA3IVoFBJYVWhloaJytVlz9N4ltKTVCQ41dXKlPla4O51y+CVehVIKQheKONro8arZE+X6bWrb619BIdiNEqhnjc1r9MYrqqJ4YpqSmaeHgmpxcOX9Drhbg70hrJ/HX1clZbDDIsMOwzy0kAhL78aJhE5OVEEdFnFgleR1zl3rQey6oYymxKkL5sKjfVna/PkqoKgoyr9tUUQqsByZ73nW1Xp84C716wHr4zEsrd18QG8QqQhh2p3qdCG2r3saZWb1FNnWqZ0AypQ9bnW5Ouk6+e0GUBewbM2s8hr0/zMkq+LrgdRuoF7aHcgtAcQ2g1o2A6Q8zKCuoLhqpoYrsgeDEYRyRl5iE+xDF6m8JVSTq+XQiagkY80zDDCzw39WvjjnuYNoFHyywERVYAoSl/4rIWuEqEsVeqtUmgKwo0roNRI9wwr9bloKCpnHbmKw8scjT4XSI2zHGKYelV6bbppd7UJUuAyBzF3y/BV9LnMdTykc0yXXSz0pBcLR+UEpZocRqp0BRp1KQxcId3Y+2dHDFfVxHBFdVGWNt8cuoqHr8TUXOgMJYfTuKnkGNAyANFtg9A/0h9uLKZBRES1TZctBa/MZECXKd3IW5dV8FzedMGjrg0ZLcoU2NSe0pBQi9eeJeerPQqmvQqCnlIqppNwTCqmk3hMKkRSXIMWRXq3egB+zetWT54TY7iqJoYrcjRGo4h/MqVer/jUHPx5Ix07/voHyRmFZXvVChn6tvDHsDaBGNyqIbxcef0WERE5AFGUesZ0WVLPUdHgVe50scCmy5aeAUCmKBZ2rAQh82uvUuZ72n74qNEI3PlbClqmwJVyqeR6Gu+CsFUQuII7S71zZHMMV9XEcEXOwGgUcToxDdv/Ssb2P5NxPSXHvEwhExDV1A/RbYNwb+uG8PeooxdWExER2ZrRKFWHVKgdZ/hpdgqQeLygZ+s4kHhCKgJTlCADGrYt7NkK7Q54h9XtzyiK0lDjzGRp+GhGUuHrzGQgMwl4dKdULMaOGK6qieGKnI0oiriQnIlf/0zGjj+TcfGfTPMyQQC6RfhiWJtADGsbiGBvViwiIiKq0wx64J8/C3u2Eo4VVHMsxj3QcihhUPvaq1Spzy0MSBlFwlJmUkGIKphX3s2xn/8T8A6tnTaXguGqmhiuyNldvZ1l7tE6k2g5rrtDiBeGtQ3CsLaBaNzAzU4tJCIiokpJvyFdr2UKXEmnS1YAlauB4E5FAld3wD2gcu9jNEi3qDD3NCUVC00Fj9y7Fd+niy/gGQx4BAIeQdLDMwjwCAYi7rH7cEeGq2piuKL65EZaLnb8KQWt49dTUfQvQstADwxtE4jodoGIbOgBoS4PLSAiIqJC+lzg5knLa7es3RjdJ6IwaIV0l3q2zD1NBc8ZNwtCU7L0EA0Va4PCpSAkmR6BBSGqSIByD5QqhtZhDFfVxHBF9dXtTC12npOC1pErKcg3Fv55iPBzxdC2gYhuG4QOIV4MWkRERI5EFKXy+Am/FzyOA7fOocwbQ5dGkAFuAYW9Sx6BxV4XPGu86/Y1XxXEcFVNDFdEQFqODnvO38KvfybjwKXb0OUXlsEN8tJgaME1Wt0ifCGXOf4fTiIiononL10qjmHq2brxPwCCZW+TtdduAfXqJscMV9XEcEVkKVubj9iLt/Hrn0nYd+EWsnWFwwH83FQY0qYhhrUNQlQTP6gUvOcGEREROQ+Gq2piuCIqXZ7egN8u3cH2v5Kx69w/SM/Vm5d5ahQY3KohhrYNRL8W/tAobXzvDyIiIqJaxnBVTQxXRBWjNxjx+9VUbP8rCTv++ge3M7XmZS5KOQa09MfQNoGIDPRAA3c1fFxVHEJIREREDoXhqpoYrogqz2AUcTL+Ln4tqDx4Iy23xDoyAfB1U8PfQ40G7ir4u6vRoOB1A3e1+eHvoYavG4MYERER2R/DVTUxXBFVjyiK+PNGBrb/lYTYi7eRlJ6Huzk6VOavjRTEioaugtceaotQ5u8uBTGFnNd6ERERke0xXFUTwxWR7eUbjEjN1uF2lha3M7W4k6XDnSwt7mRqpeeC6duZWqRWMogJAuDjqrLoAZN6xwpCmSmQuavhrlFAJZdBKRdYTp6IiIjKVZlsUH9qKBKRXSnkMgR4ahDgWf6NAvMNRqTm6HAnsyCAFTyKhjLT69RsLYwikJqtQ2q2Dn//k1Wh9ggCoJTLoJbLoFLIoFZIz+aH3PRaDpW8yHJ54TrqYutbTstL7EtdbDtvFxVcVCz6QURE5CwYroiozlHIZQjw0CDAo/wgZjCKuJujKwhbBY+CUHa7oEfMtCw1WwdDwY2RRRHQ5Rul+3dpy3mTGiITgGYB7ugQ4o32od7oEOKFloGeLGdPRETkoDgs0AoOCyRyTkajCG1BoNIaDOZwpTMYC1/nG6EtPp1vhC7fYLFe8XUs9mEwmt+n+DJtvsE8T28o+edXJZehVZAH2od4o32IFzqEeqOpvzuLexAREdkJhwUSEVkhkwlwUckLhuIp7d0c3MrIw+nEdJxJTDM/p+XocToxHacT083ruankaNtIClrtQ7zQIcQbIT4uvGaMiIiojmHPlRXsuSIiexBFEQmpuTidmIbTCWk4k5iOP2+mI0dnKLGur5sK7Rp5oUOIl9TLFepVoWGUREREVDmsFlhNDFdEVFcYjCIu38rC6cQ0nEmUAtf5pAyrQwqDvTTmoNUhxBvtQrzgqbF/Dx0REZEjY7iqJoYrIqrLtPkGXEjKLOjhkoYTXr6dZbV8fZMGbmhf0LvVIdQbbYI9oVHWfoVCo1FEjt6AbG0+srT5RZ6ledk60zwDtHoDPDQK+Lqp4eumLHhWwddNBW8XJWS8/oyIiGoRw1U1MVwRkaPJ0ubjzxuW128lpOaWWE8hE9CioQc6hHqZi2a0aOgBZbGbMBuNInItwpDBHIqkIGQZlLJ1UjDKLraOabm1oY1VISu4p5lPQdjyc5Ne+xVMW3uoFSx3T0REVcdwVU0MV0TkDFKzddJwwoTC0HUnq2TdebVChsYN3KDLNxaGIb2hUjdyriiZALipFXBXK+BmeqjkRebJoVHIkZGnR2q2HqnZUgn9lGwdMvPyq/Se7moFfAp6wPzcVPBxVcHPvSB8uRY8uxe8dlfBQ62wSbEQURShN4jIN0qVIfUGI/JNz0YR+QUVI0ssN0rP+QYj9AXrmea7qRQI83NFhJ8bfFyVLGpCRFQLGK6qieGKiJyRKIpISs+z6N06k5heZmgxhSE3lRR8Sg9FioLXcriqis4rso1KAY1SVuVAoDcYcbcgaJmeU0t5pGTrcDen8L5mlaGUC/ApCF1+7irIBKFI8LEMO6YQpCsISUXDU1XeuzI81IVBS3p2RZivGyIauKKhh4bDJ4mIbIThqpoYroiovjAaRVxLyUZ8ag5cVQq4qgrDkLu6emHI3kRRREZuPlKytbibo0NKVkH4ytEhtejrbGnZ3RydzYYvlkYuE6CQCVDKZVDIBShkMqjkAhQF00pZwXy5DEqZIM2Ty6T1ZQLSc/W4npKD5Iy8Mt9HrZAhzNcV4UUCV5ivFMQa+biUGAZKRESl432uiIioQmQyAU383dHE393eTbE5QRDg5aqEl2vFKybm6gxIzdFZ9JAZRbFI2LEMQVLwkUKS0hSSioQnpUwGpUJarpAJNutNytMbEJ+ag+spObieki09p0qvE+/mQptvxKVbWbh0K6vEtnKZgEbeLgj3k8JXuK9bYQ+Yr2vBfeCIiKgq2HNlBXuuiIjIUekNRtxMyy0MXHeyzcErPjUHeXpjmds39FQj3NfNHL7C/NwQURDCKhNUiYicBXuuiIiI6imlXIZwPzeE+7mVWGY0iridpcW1IoFL6v2SXmfk5eOfDC3+ydDi2LXUEtt7uyoR7uuK8ILhhZ4aJTw0Cni6FDxrFAXzpGlXldxhh5USEVUFe66sYM8VERHVR2k5OlxLsQxd8anZuJaSg9uZJStNlkcuE+ChURQEL2XBa2VhKCsSzIrON0+7KFhKvw4SRdOtGgzI1RmQrctHTsHtF3J0Bum1zoBc8zzpdgy6fCPkMgGCIEAuA2SCUOSBEssEQYC8YJlMJq1nuV3hfNMy8zbF9l98mUouR5C3Bo28Xexy7z9yLOy5IiIiokrzdlWho6sKHUO9SyzL1uZbXOeVlJ6HzLx8ZObpkZGnL3idb35tKKiYmJajR1qOHkDJ+65VhEohK9IjVhi6PNSFvWbuagVcVHJolDJoFHJolHKolTLpWSE9a5RyaIq8lteDaoqiKCJPb0S2Lt8cgooHohydATla03RBELKYlu5fZwpTOTrptTP917y/hxqNvF0Q4uOCEB9XNPKRXof6uKCRN69DpMphz5UV7LkiIiKqOlPPRkauKXzlFwlgevP8zDLmZ2qrdl+zilLKBWgUcqiVBaFMWRjO1FZCmjRdZL2CedZCnFEUoc8vvH+ZzmCE3vyQ5pmWF1+myzdK9z7LL75twXS+0Vzu3/TavE/z8sL7p9U0V5XcXGnUteD2DObXKin0muYp5TKIogijCBiMIkRRhKFg2iiKMBqtLxNFKagbRRSsU7CeKJa6THoufVmuzoCbabnIrkCFUD83VYngFVIQvEJ8XOCmZl+Fs2PPFREREdmNIAgFX7gVCPTSVGkfBqOILG05YazIs1ZvQJ7eCG2+9JynNyCvyGutXgoqJlIgqfkQV1e4KOVwU8ulsGMOQ4oSgci14J52LirpXnaF6xQNUYU3/Hbk+6mJooj0XD0S7+Yi8W5OwXOuefrG3VxkavORUlA99HRiutX9+LgqpdBVELZCfFzQyKfwtYeGhWDqE/ZcWcGeKyIiIudjMIoW4UubXxDCCoJZXr7BHNLM8/ON0BYsM62nLRbc8ooFO7lMgLKgVL9KITOX7Dfds8y8zDStKLmscLkApUJmLutvucz6ctMyhVyAi1IOF6VjhyB7ksKXFLxuFA1eadLr9Fx9ufvw1CgQUhC2GhX0gJmCV4i3KzxdFCz8UsfxJsLVxHBFREREROXJzNNLQSu1sPfLFLwS7+bgbk754ct0zaCqeAhXSDcZLwzeMqgUxaZNyxXFpiu8fclQbhriqlbIGMoLcFggEREREVEN89Ao0TJQiZaB1r9wZ2vzC8JWTpGer8LerztZOmRp85FVR4enFl5LKIOL0nQdolQcxkVVeC2ii0oOdcF1ikXXLbxO0bKoTNFt1QW9q0q54BQ9eAxXREREREQ1wE2tQIuGHmjR0MPq8lydAUnpudDmG4sUJRGLFDkxQmcwFUgpMm0uilJkutj2OvNy60VRrBVC0RmMMBgLB7Vp843Q5huRXrVin5UiEyAFL2WRYjIKOb55tDv8PdQ13wAbYbgiIiIiIrIDF5UcTfzd7d0MC/kGI/Isrkcsen2hEblF5+cbkaczWBSQMS3XFmyTW2IfBvP+i5b1N4owl/8vytFGJjJcERERERERAEAhl8FdLoN7LZSYF0Wpt8xUKCa3WAjL1Rvg6eJY1RYZroiIiIiIqNYJggC1QrpeCw4Wokojs3cDiIiIiIiInAHDFRERERERkQ0wXBEREREREdkAwxUREREREZENMFwRERERERHZAMMVERERERGRDTBcERERERER2QDDFRERERERkQ0wXBEREREREdkAwxUREREREZENMFwRERERERHZAMMVERERERGRDTBcERERERER2QDDFRERERERkQ0o7N2AukgURQBARkaGnVtCRERERET2ZMoEpoxQFoYrK1JSUgAAoaGhdm4JERERERHVBZmZmfDy8ipzHYYrK3x9fQEA8fHx5R5AqryMjAyEhoYiISEBnp6e9m6O0+HxrVk8vjWPx7hm8fjWLB7fmsXjW7N4fK0TRRGZmZkIDg4ud12GKytkMulSNC8vL55YNcjT05PHtwbx+NYsHt+ax2Ncs3h8axaPb83i8a1ZPL4lVbTDhQUtiIiIiIiIbIDhioiIiIiIyAYYrqxQq9VYsGAB1Gq1vZvilHh8axaPb83i8a15PMY1i8e3ZvH41iwe35rF41t9gliRmoJERERERERUJvZcERERERER2QDDFRERERERkQ0wXBEREREREdkAwxUREREREZEN1NtwtWLFCjRu3BgajQZdunTBwYMHy1x///796NKlCzQaDZo0aYLPPvusllrqWBYtWoRu3brBw8MDAQEBGDNmDC5evFjmNrGxsRAEocTjwoULtdRqx7Fw4cISxykwMLDMbXjuVk5ERITV83HWrFlW1+f5W7YDBw5g1KhRCA4OhiAI2LJli8VyURSxcOFCBAcHw8XFBf3798dff/1V7n5jYmLQunVrqNVqtG7dGps3b66hT1C3lXV89Xo95s6di3bt2sHNzQ3BwcGYOnUqbt68WeY+16xZY/WczsvLq+FPU/eUd/5Onz69xHHq2bNnufvl+Ssp7/haOw8FQcD7779f6j55/koq8n2Mf39rRr0MVxs2bMDzzz+PV155BSdPnkSfPn0QHR2N+Ph4q+vHxcVh+PDh6NOnD06ePImXX34Zzz77LGJiYmq55XXf/v37MWvWLBw9ehS7du1Cfn4+hgwZguzs7HK3vXjxIpKSksyP5s2b10KLHU+bNm0sjtPZs2dLXZfnbuUdP37c4vju2rULAPDAAw+UuR3PX+uys7PRoUMHfPLJJ1aXL168GB988AE++eQTHD9+HIGBgbj33nuRmZlZ6j6PHDmCiRMnYsqUKTh9+jSmTJmCCRMm4Pfff6+pj1FnlXV8c3Jy8Mcff2D+/Pn4448/8NNPP+Hvv//GfffdV+5+PT09Lc7npKQkaDSamvgIdVp55y8A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",
      "text/plain": [
       "<Figure size 1000x500 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "import os\n",
    "os.environ['KMP_DUPLICATE_LIB_OK']='True'\n",
    "# Calculate and print accuracies for training and cross-validation sets\n",
    "model.eval()\n",
    "with torch.no_grad():\n",
    "    # Training set accuracy\n",
    "    tr_correct = 0\n",
    "    tr_total = 0\n",
    "    for images, labels in trLoader:\n",
    "        outputs = model(images)\n",
    "        _, predicted = torch.max(outputs, 1)\n",
    "        _, true_labels = torch.max(labels, 1)\n",
    "        tr_total += labels.size(0)\n",
    "        tr_correct += (predicted == true_labels).sum().item()\n",
    "    \n",
    "    tr_accuracy = 100 * tr_correct / tr_total\n",
    "    \n",
    "    # Test set accuracy\n",
    "    cv_correct = 0\n",
    "    cv_total = 0\n",
    "    for images, labels in cvLoader:\n",
    "        outputs = model(images)\n",
    "        _, predicted = torch.max(outputs, 1)\n",
    "        _, true_labels = torch.max(labels, 1)\n",
    "        cv_total += labels.size(0)\n",
    "        cv_correct += (predicted == true_labels).sum().item()\n",
    "    \n",
    "    cv_accuracy = 100 * cv_correct / cv_total\n",
    "\n",
    "print(f'Accuracy on training set: {tr_accuracy:.2f}%')\n",
    "print(f'Accuracy on cross-validation set: {cv_accuracy:.2f}%')\n",
    "\n",
    "# Plot training and cross-validation losses\n",
    "plt.figure(figsize=(10, 5))\n",
    "plt.plot(range(1, num_epochs+1), train_losses, label='Training Loss')\n",
    "plt.plot(range(1, num_epochs+1), cv_losses, label='Cross-Validation Loss')\n",
    "plt.xlabel('Epoch')\n",
    "plt.ylabel('Loss')\n",
    "plt.title('Training and Cross-Validation Loss')\n",
    "plt.legend()\n",
    "plt.show()"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
